[WIP]React 核心概念
创建: 2019/05/01
Hello World | |||||
ReactDOM.render( <p>sample</p>, document.getElementById('root') );
|
|||||
JSX简介 | |||||
插值 |
大括号 {} ● 内部可放任何JavaScript表达式 const jsxElement = <p sampleProp={0}>{buildName(people)}</p>;
|
||||
jsx也是表达式 |
被编译成函数 ● 可以赋值给变量 const buildName = (people) => { return `${people.sex}的${people.name}` }; const people = { name: '妖怪', sex: '不男不女', } const jsxElement = <p sampleProp={0}>{buildName(people)}</p>;
|
||||
指定属性 |
和html一样, 但要用驼峰写法(因为JSX是JS) ● 赋值可以双引号可以用插值(不要组合起来用) // 双引号 <p sampleA="0"/> // 插值 <p sampleB={1}/>
|
||||
嵌套 |
● JSX内部可以嵌套JSX <p>测试
<a src={link.url}>{link.text}</a>
</p>
● 对于空标签, 可以 /> 结尾 const blankElement = <p/>;
|
||||
自动转义 |
JSX的所有内容自动转义 ● 可以直接插入用户输入内容, 不用担心安全问题
|
||||
JSX 表示对象 |
Babel 会把 JSX 转译成一个名为 React.createElement() 函数调用 // JSX const element = ( <h1 className="greeting"> Hello, world! </h1> ); // React.createElement const element = React.createElement( 'h1', {className: 'greeting'}, 'Hello, world!' ); // 实际生成 const element = { type: 'h1', props: { className: 'greeting', children: 'Hello, world!' } };
|
||||
元素渲染 | |||||
根节点 |
该节点内的所有内容都将由 React DOM 管理 ● 可以有任意多个根节点 |
||||
渲染 |
ReactDOM.render(reactDOM, dom)
将一个 React 元素渲染到根 DOM 节点中 ● 参数
|
||||
更新已渲染的元素 |
重新调用ReactDOM.render ● React自动对比新旧ReactDOM, 只更新变化的部分
|
||||
组件&Props | |||||
定义组件 |
组件名称必须以大写字母开头 ● 函数组件 function Welcome(props) { return <h1>Hello, {props.name}</h1>; }
● class组件 |
||||
渲染组件 | 接收到的参数会作为props传入 | ||||
组合组件 | 组件可以互相嵌套 | ||||
Props 的只读性 |
所有 React 组件都必须像纯函数一样保护它们的 props 不被更改 ● 需要实时变化的属性放入state |
||||
state&生命周期 | |||||
生命周期函数 |
|
||||
state |
React通过this.state来检测自身是否被改变 ● 更新用setState(), 不要直接修改State this.setState({a:1})
如果要用到之前的props或states, 不可以直接在setState里面调用. 用函数 this.setState((state, props) => ({ counter: state.counter + props.increment }));
● 只有构造函数可以给state赋值 class Sample extends React.Component { constructor(props) { super(props); this.state = {...} // 构造函数处可以给state赋值 } } ● setState()是浅合并 参数里没提到的保持原样
|
||||
事件处理 | |||||
js关于事件处理相关 | |||||
React 事件的命名采用小驼峰式 例: onClick |
|||||
阻止默认事件 |
不能用return false 必须用 preventDefault |
||||
添加事件 |
一般不需要 addEventListener , 只需在渲染时添加监听器 ● 监听函数设置成箭头函数, 以确保this正确 class Events extends React.Component { constructor(props) { super(props); } clickHandle = e => { console.log(e); }; render() { return ( <div> <h1>title: events</h1> <p onClick={this.clickHandle}>click</p> </div> ); } } ● 若不设置为箭头函数, 为确保this正确
|
||||
向事件函数传递参数 |
React的事件对象 e 会被作为第二个参数传递
|
||||
条件渲染 | |||||
阻止渲染 | render内部返回null | ||||
与运算符&& |
a && b 若a可转换为 |
||||
三项运算符 |
con ? a : b
|
||||
列表&key | |||||
构建列表组件 |
class ListKey extends React.Component { constructor(props) { super(props); this.datas = new Array(10).fill(Math.random()*100).map((v, i) => {return v+i}); this.listItems = this.datas.map((v, i) => { return ( <li key={i}>data: {parseInt(v)}</li> ); }); } render() { return ( <div> <h1>title: list & key</h1> <ul>{this.listItems}</ul> </div> ); } }
|
||||
key |
key 帮助 React 识别哪些元素改变了,比如被添加或删除。因此你应当给数组中的每一个元素赋予一个确定的标识。 ● 尽量在 this.datas = new Array(10).fill(Math.random()*100).map((v, i) => {return v+i}); this.listItems = this.datas.map((v, i) => { return ( <li key={i}>data: {parseInt(v)}</li> ); });
● 数组元素中使用的 key 在其兄弟节点之间应该是独一无二的 ● key 会传递信息给 React ,但不会传递给你的组件 需要key值的用其他属性名显示传递 <li key={i} mykey={i}>data: {parseInt(v)}</li>
|
||||
表单 | |||||
受控组件 |
所有事件都需要添加处理函数 class Reservation extends React.Component { constructor(props) { super(props); this.state = { isGoing: true, numberOfGuests: 2 }; this.handleInputChange = this.handleInputChange.bind(this); } handleInputChange(event) { const target = event.target; const value = target.type === 'checkbox' ? target.checked : target.value; const name = target.name; this.setState({ [name]: value }); } render() { return ( <form> <label> 参与: <input name="isGoing" type="checkbox" checked={this.state.isGoing} onChange={this.handleInputChange} /> </label> <br /> <label> 来宾人数: <input name="numberOfGuests" type="number" value={this.state.numberOfGuests} onChange={this.handleInputChange} /> </label> </form> ); } }
|
||||
状态提升 | |||||
将多个组件中需要共享的 state 向上移动到它们的最近共同父组件中,便可实现共享 state。这就是所谓的“状态提升” | |||||
组合&继承 | |||||
包含关系 |
● 嵌套的组件全部在 props.children 里 ● 预留placeholder可以用任何名字, 可以传入任何对象 function SplitPane(props) { return ( <div className="SplitPane"> <div className="SplitPane-left"> {props.left} </div> <div className="SplitPane-right"> {props.right} </div> </div> ); } function App() { return ( <SplitPane left={ <Contacts /> } right={ <Chat /> } /> ); }
|
||||
特例关系 |
“特殊”组件可以通过 props 定制并渲染“一般”组件 function Dialog(props) { return ( <FancyBorder color="blue"> <h1 className="Dialog-title"> {props.title} </h1> <p className="Dialog-message"> {props.message} </p> </FancyBorder> ); } function WelcomeDialog() { return ( <Dialog title="Welcome" message="Thank you for visiting our spacecraft!" /> ); }
|
||||
继承 | 不需要使用 | ||||
React哲学 | |||||
用 React 创建一个静态版本 |
渲染 UI 和添加交互分开 |
||||
确定 UI state 的最小(且完整)表示 |
通过问自己以下三个问题,你可以逐个检查相应数据是否属于 state:
|
||||
确定 state 放置的位置 |
对于应用中的每一个 state:
|
||||
添加反向数据流 | 回调 |