React项目指导
使用webpack需要安装的依赖
webpack
,webpack-cli
,react
,react-dom
babel-loader
,@babel/core
,@babel/preset-env
,@babel/preset-react
设置.babelrc
,{"presets": ["@babel/preset-env","@babel/preset-react"]}
设置scripts
:
1 2
| "dev": "webpack --mode development", "build": "webpack --mode production"
|
设置webpack-dev-server
:
1 2 3 4 5 6 7
| devServer: { compress: true, port: 9000, hot: true },
"start": "webpack-dev-server --config webpack.config.js"
|
设置performance
:
1 2 3
| performance: { hints: false }
|
Component
基本组件
1 2 3
| let title = <h1>Hello, world!</h1>
ReactDOM.render(title,document.getElementById('root'))
|
动态组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import React from 'react'; import ReactDOM from 'react-dom';
let displayTime = () => { let nowTime = ( <div> <span>现在时间:{new Date().toLocaleTimeString()}</span> </div> ); ReactDOM.render(t nowTime, document.getElementById('root') ); };
setInterval(displayTime, 1000);
|
class
组件构建器
1 2 3 4 5 6 7 8 9 10 11 12 13
| import React, {Component} from 'react'; import ReactDOM from 'react-dom';
class HelloTitle extends Component { render() { return <h1>Hello,World!</h1> } }
ReactDOM.render( <HelloTitle/>, document.getElementById('root') );
|
props
属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| import React, {Component} from 'react'; import ReactDOM from 'react-dom';
class HelloTitle extends Component { render() { return <h1>Hello,{this.props.name}!</h1> } }
let titleDiv = ( <div> <HelloTitle name="React"/> <HelloTitle name="World"/> </div> );
ReactDOM.render( titleDiv, document.getElementById('root') );
|
props
多层使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| import React, {Component} from 'react'; import ReactDOM from 'react-dom';
class HelloTitle extends Component { render() { return <h1>Hello,{this.props.name}!</h1> } }
class HelloDiv extends Component { render() { return <div><HelloTitle name={this.props.name}/></div> } }
ReactDOM.render( <HelloDiv name="React"/>, document.getElementById('root') );
|
组件复用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| import React, {Component} from 'react'; import ReactDOM from 'react-dom';
class HelloTitle extends Component { render() { return <h1 style={this.props.style}>{this.props.content}</h1> } }
class HelloDiv extends Component { render() { return <div> <HelloTitle content="比较大的字" style={{'fontSize': 18}}/> <HelloTitle content="比较小的字" style={{'fontSize': 12}}/> </div> } }
ReactDOM.render( <HelloDiv/>, document.getElementById('root') );
|
Component的状态state和生命周期
state属性
1 2 3 4 5 6 7 8 9 10
| constructor(props) { super(props); this.state = { time: new Date().toLocaleTimeString() } }
render() { return <h1>现在时间是{this.state.time}</h1> }
|
组件构建完成后先执行的动作,componentDidMount()
:
1 2 3 4 5 6
| componentDidMount() { let upTime = () => { this.setState({time: new Date().toLocaleTimeString()}) }; setInterval(upTime, 1000) }
|
setState()修改状态值
1
| this.setState({time: new Date().toLocaleTimeString()})
|
生命周期
- 在
constructor
中初始化组件内部的资料。
- 使用
render()
在网页上输出组件内容。
- 输出后会执行
componentDidMount()
进行一次调用。
- 当组件内部的
state
值被修改时执行componentDidUpdate()
。
- 当组件被移除时会执行
componentWillUnmount()
的内容一次。
componentDidMount()
- Component已经
render
到实体DOM阶段完成的时候触发;
- 此
method
只会被呼叫一次;
- 在这裡可以
setState()
,并会再次重新render
、component
一次;
- 可以放入具有
side effect
的function
,如setInterval
、呼叫API等等。
componentWillUnmount()
- Component即将从实体DOM阶段移除「之前」的时候触发;
- 也是只会被呼叫一次;
- 不可以在这裡使用
setState()
;
- 也可以放入具有
side effect
的function
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| class Clock extends Component { constructor(props) { super(props); this.state = { currentTime: new Date().toLocaleString() } }
componentDidMount() { this.timer = setInterval(this.updateTime, 1000) }
componentWillUnmount() { clearInterval(this.timer) }
updateTime = () => { this.setState({ currentTime: new Date().toLocaleString() }) };
render() { const {currentTime} = this.state; return ( <div className="clock"> <div>{currentTime}</div> </div> ) } }
|
component各阶段的生命周期方法
- 挂载(
Mounting
):组件一开始呈现到真实网页的过程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| class LifeCycle extends Component { constructor(props) { super(props); }
static getDerivedStateFromProps(nextProps, prevState) { }
UNSAFE_componentWillMount() { }
render() { return ( <div></div> ) }
componentDidMount() { } }
|
- 更新(Updating):使用者的操作中,组件的状态和属性被改变
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| class LifeCycle extends Component { UNSAFE_componentWillReceiveProps(nextProps) { }
static getDerivedStateFromProps(nextProps, prevState) { }
shouldComponentUpdate() { }
UNSAFE_componentWillUpdate(nextProps, nextState) { }
getSnapshotBeforeUpdate(prevProps, prevState) { }
componentDidUpdate(prevProps, prevState, snapshot) { } }
|
- 卸载(Unmounting):组件要移除真实DOM的阶段
1 2 3 4 5 6 7
| class LifeCycle extends Component { componentWillMount() { } }
|
catch error
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| class ErrorBoundary extends Component { constructor(props) { super(props); this.state = { hasError: false } }
componentDidCatch(error, info) {
this.setState({hasError: true}); logErrorMyService(error, info); }
render() { if (this.state.hasError) { return <h1>Something went wrong...</h1> } return this.props.children } }
|
上面就是component
可以使用的生命周期方法,最常用主要是这些:
constructor()
render()
componentDidMount()
compoinentDidUpdate()
componentWillUnmount()
Component的事件处理
- 取得触发事件的DOM
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| class InputGender extends Component { constructor(props) { super(props); this.state = { gender: '' }; this.changeGender = this.changeGender.bind(this) }
changeGender(event) { console.log(event.target.value); this.setState({ gender: event.target.value }); }
componentDidUpdate() { console.log(`已将state.gender变动为:${this.state.gender}`) }
render() { return ( <select onChange={this.changeGender}> <option value="M">男</option> <option value="W">女</option> </select> ) } }
|
1 2 3 4 5 6 7
| class HelloTitle extends Component { render() { return <h1>{this.props.title}</h1> } }
{(this.state.gender === 'M') ? <HelloTitle title="先生"/> : <HelloTitle title="女士"/>}
|
用绑定的state取得输入资料
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| class EasyForm extends Component { constructor(props) { super(props); this.state = { name: "" }; this.changeState = this.changeState.bind(this); this.submitForm = this.submitForm.bind(this); }
changeState(event) { this.setState({ name: event.target.value, }); }
submitForm(event) { let element = document.querySelector('span'); element.innerHTML = `${this.state.name}`; event.preventDefault() }
render() { return ( <div> <form onSubmit={this.submitForm}> <label>姓名:</label> <input id="name" name="name" onChange={this.changeState} value={this.state.name}/> <input type="submit" value="提交" style={{'marginLeft': 6}}/> </form> <p>现在输入的名字是:<span style={{'color': '#FF7F24'}}></span></p> </div> ) } }
|
受控组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| class EasyForm extends Component { constructor(props) { super(props); this.state = { lists: [ {id: '01', listName: '写文章', check: false}, {id: '02', listName: '写代码', check: false}, {id: '03', listName: '旅游', check: true}, {id: '04', listName: '踢球', check: true}, {id: '05', listName: '公益', check: false}, ] }; this.submitForm = this.submitForm.bind(this); this.changeState = this.changeState.bind(this); }
changeState(index) { let arrLists = this.state.lists; arrLists[index].check ? arrLists[index].check = false : arrLists[index].check = true; this.setState({ lists: arrLists, }); }
submitForm(event) { let status = "目前做了:"; this.state.lists.map((list) => list.check ? status += `${list.listName} ` : ''); console.log(status); event.preventDefault() }
render() { let lists = this.state.lists.map((list, index) => ( <div key={list.id}> <input type="checkbox" checked={list.check} onChange={this.changeState.bind(this, index)} key={list.id} /> <label>{list.listName}</label> </div> )); return ( <form onSubmit={this.submitForm}> <div> <label>每日待办清单:</label> {lists} </div> <input type="submit" value="发送表单"/> </form> ) } }
|
非受控组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| class EasyForm extends Component { constructor(props) { super(props); this.submitForm = this.submitForm.bind(this); this.filebox = React.createRef() }
submitForm(event) { console.log(`选择文档为:${this.filebox.current.files[0].name}`) event.preventDefault() }
render() { return ( <form onSubmit={this.submitForm}> <div> <label>上传文档:</label> <input type="file" ref={this.filebox}/> </div> <input type="submit" value="送出表单"/> </form> ) } }
|
refs操作DOM
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| class App extends Component { constructor() { super(); this.state = { itemList: [] }; this.addFile = React.createRef(); }
addItem = () => { const {itemList} = this.state; const tempList = Object.assign([], itemList); if (this.addFile.current.value !== '') { tempList.push(this.addFile.current.value); } this.setState({ itemList: tempList }); this.addFile.current.value = '' };
render() { const {itemList} = this.state; return ( <div className="App"> <input type="text" name="addFile" ref={this.addFile}/> <input type="button" onClick={this.addItem} value="ADD"/> <ul className="list"> {itemList.map((item, index) => <li key={`item_${index}`}>{item}</li> )} </ul> </div> ); } }
|
实例:TODOLIST
TodoList.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
| class TodoList extends Component { constructor(props) { super(props); this.state = { list: [] } }
addItem = (text) => { const {list} = this.state; if (text !== '') { const tempArr = list.concat({ id: list.length + 1, text, status: false }); this.setState({list: tempArr}) } };
toggleStatus = (id) => { const {list} = this.state; const tempArr = list.map(item => { if (item.id.toString() === id.toString()) { return ({ id: item.id, text: item.text, status: !item.status }) } return item; }); this.setState({list: tempArr}) };
render() {
const {list} = this.state; const divStyle = { width: '250px', margin: 'auto', textAlign: 'left' }; return ( <div style={divStyle}> <TodoForm onAddItem={this.addItem}/> <ul> {list.map(item => ( <TodoItem key={item.id} id={item.id} status={item.status} onItemClick={this.toggleStatus} > {item.text} </TodoItem> ))} </ul> </div> ) } }
|
TodoForm.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| class TodoForm extends Component { constructor(props) { super(props); this.inputRef = React.createRef(); }
formSubmit = (e) => { const {onAddItem} = this.props; e.preventDefault(); onAddItem(this.inputRef.current.value); this.inputRef.current.value = '' };
render() { return ( <form onSubmit={this.formSubmit}> <input type="text" name="todoItem" ref={this.inputRef} autoComplete="off"/> <button type="submit" value="submit">submit</button> </form> ) } }
|
TodoItem.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| class TodoItem extends Component { handleItemClick = (e) => { const {onItemClick} = this.props; onItemClick(e.target.id) };
render() { const {children, id, status} = this.props; return ( <li id={id} onClick={this.handleItemClick} data-status={status} style={ status ? {textDecoration: 'line-through'} : {textDecoration: 'none'} } > {children} </li> ) } }
|