翻译自react的大部分文档,方便本身查阅。javascript
仅仅关于客户端的Reacthtml
不能直接设置state
, 这不会再次渲染一个component(this will not re-render a component), 只有一个地方能够直接设置state。java
// wrong, this this.state = { comments: 'Hello world'};
应该使用setState()
方法。react
// true this.setState({ comments: 'Hello world', });
React能够将多个setState()
调用分批到单个更新中以实现性能。git
由于this.props
与this.state
均可能是异步更新,所以不能够依靠它们的值来计算下一次的state。举例来讲,下面就是错的:es6
// wrong this.setState({ counter: this.state.counter + this.props.increment, });
为了解决这个问题,使用setState()
的第二种形式,它接受一个函数,函数的第一个参数是以前的state, 第二个参数是props。github
// correct this.setState((prevState, props) => ({ counter: prevState.counter + props.increment, }));
当你调用setState()
的时候,React合并你提供的对象到当前的state当中。(When you call setState(), React merges the object you provide into the current state.)segmentfault
function MailBox(props) { return ( <div> <h1>Hello!</h1> {unreadMessages.length > 0 && <h2> You have {unreadMessages.length} unread messages. </h2> } </div> ); }
可是这种方法,值得注意的是,return后面跟的最外层必须是html元素。而不能是下面这样:数组
function MailBox(props) { return ( {unreadMessages.length > 0 && <h2> You have {unreadMessages.length} unread messages. </h2> } ); }
render() { const isLoggedIn = this.state.isLoggedIn; return( <div> The user is <b>{isLogginIn ? 'currently' : 'not'}</b> logged in. </div> ); }
还能够用于更大的表达式。浏览器
render() { const isLoggedIn = this.state.isLoggedIn; return ( <div> {isLoggedIn ? ( <LogoutButton onClick={this.handleLogoutClick} /> ) : ( <LoginButton onClick={this.handleLoginClick} /> )} </div> ); }
极少的状况下,要让组件隐藏起来,那么能够经过return null
来实现。
在react中使用list,必需要为每一个list的元素指定key(每一个item的key是惟一的)。
keys帮助React肯定哪些item已经改变了,被添加了或者被移除了。
不推荐设置key的值是索引,若是这个数组要被排序的话(We don't recommand using indexes for keys if the items can reorder, as that would be slow.)。由于这将会被慢。
key只在周围数组的上下文中有意义。
在react中,HTML表单元素与其余DOM元素有所不同。由于表单元素天然保持着一些内部状态。举例来讲,这个HTML格式的表单接受一个单个的name:
<form>
<label>
Name:
<input type="text" name="name" />
</label>
<input type="submit" value="Submit" />
</form>
这个表单拥有HTML表单的默认行为,当提交表单的时候,浏览器会打开一个新的页面。若是你在react中这么使用的话,它依然起做用。可是在大多数状况下,拥有一个能够处理表单并可访问用户输入表单的数据的JavaScript函数是很方便的。实现这一点的标准方法是使用一种叫做'受控组件'的技术。
在HTML中,相似于input textarea select
这样的表单元素一般维持着它们本身的状态,而且基于用户的输入更新。在React中,可变状态一般保存在组件的state
属性中,而且只能经过setState()
来更新。
咱们能够经过使react成为'真正的惟一来源', 将二者结合起来。而后,呈现表单的React组件也控制后续用户输入时该表单中发生的状况。 一个输入表单元素的值被React控制,被称为受控组件。
一个简单的受控组件以下:
class NameForm extends React.Component { constructor(props) { super(props); this.state = {value: '',}; this.handleChange = this.handleChange.bind(this); this.handleSubmit = this.handleSubmit.bind(this); } handleChange(e) { this.setState({ value: e.target.value, }); } handleSubmit(e) { console.log(this.state.value); e.preventDefault(); } render() { return ( <form onSubmit={this.handleSubmit}> <label> name: <input type="text" value={this.state.value} onChange={this.handleChange} /> </labeL> <input type="submit" value="Submit" /> </form> ); } }
使用受控组件,每一个状态的突变都具备相关联的处理函数。这使得修改或验证用户的输入很直接。举例来讲,若是咱们想要用户强制性这些名称用所有大写字母写,咱们能够把handleChange写为:
handleChange(e) { this.setState({ value: e.target.value.toUpperCase(), }); }
在HTML中,一个textarea
元素定义它的文本经过children来定义。
而在React中,一个textarea
元素是使用value属性来定义的。其使用方法和input
差很少的。
在HTML中,select建立一个下拉列表,好比像下面这样的:
<select> <option value="baoma">baoma</option> <option selected value="benchi">benchi</option> <option value="aodi">aodi</option> </select>
而在React中,是在根select组件里使用value属性来选中的。在受控组件中,这更加方便,由于你只须要在一个地方更新它,好比下面这样:
class FormItem extends React.Component { constructor(props) { super(props); this.state = {value: 'benchi'}; this.handleChange = this.handleChange.bind(this); this.handleSubmit = this.handleSubmit.bind(this); } handleChange(e) { this.setState({ value: e.target.value, }); } handleSubmit(e) { console.log(e.state.value); e.preventDefault(); } render( return ( <form onSubmit={this.handleSubmit} <label> Pick your favorite car: <select value={this.state.value} onChange={this.handleChange}> <option value="baoma">baoma</option> <option value="benchi">benchi</option> <option value="aodi">aodi</option> </select> </label> <input type="submit" value="Submit" /> /> ); ); } <input type="text" /> <textarea> <select>它们都工做的差很少,它们都接受一个属性,这个属性能够用来实现一个受控组件。value
当你须要处理多个受控组件input
元素的时候,你能够给每一个元素添加name
属性,而且让处理函数根据该值(event.target.name)选择要进行的操做。
举个例子:
class Reservation extends React.Component { constructor(props) { super(props); this.setState = { isGoing: true, numberOfGuests: 2, }; this.handleChange = this.handleChange.bind(this); } handleChange(e) { const target = e.target; const value = target.type === 'checkbox' ? target.checked : target.value; const name = target.name; // es6 computed property name this.setState({ [name]: value, }); } render() { return ( <form> <label> Is going: <Input name="isGoing" type="checkbox" checked={this.state.isGoing} onChange={this.handleChange} /> </label> </br> <label> Number of guests: <input name="numberOfGuests" type="number" value=={this.state.numberOfGuests} onChange={this.handleChange} /> </label> </form> ); } }
可能你以为太麻烦,你须要非受控组件
在react中,共享state是经过将它移动到须要它的组件的最接近的共同祖先来实现的。这被称为提高状态。若是祖先拥有了共享状态,那么就有了source of true
。
官方文档给的那个例子,简单来讲,两个组件的值相互依赖的时候,就将state提高到它们最近的共同祖先,经过在父组件里进行相应的值转换,而后经过props将值传递给子组件。而后两个子组件的值改变时,调用的函数是父组件传递下来的。
所以, 能够经过子组件调父组件传递过来的函数,将子组件的值传递给父组件, 来改变父组件的state, 而后父组件计算值后,经过props将计算后的值分发到各个子组件,这样就保证了惟一的来源,而子组件的值也是相互依赖(有关联)的。 以下:
// 子组件 handleChange(e) { this.props.onTemperatureChange(e.target.value); } <input onChange={this.handleChange} type="text" /> // 父组件 handleChange(value) { this.setState({ temperature: value, }); } <TemperatureInput onTemperatureChage={this.handleChange} />
在React中,咱们推荐使用组合来复用代码而不是继承。
一些容器不能提早知道它们的children是谁。在Sidebar
和Dialog
里尤为的正常。
咱们推荐这类的组件使用特殊的children
prop来将children直接传递到它们的输出中:
function FancyBorder(props) { return ( <div className={'FancyBorder FancyBorder-' + props.color}> {this.props.children} </div> ); }
而后让其余组件经过嵌入JSX传递任意个child给FancyBorder
:
function WelcomeDialog() { return ( <FancyBorder color="blue"> <h1 className="Dialog-title"> Welcome </h1> <p className="Dialog-message"> Thank you for visiting our spacecraft! </p> </FancyBorder> ); }
<FancyBorder>
JSX标签中的任何内容都会做为子菜单传入FancyBorder组件。因为FancyBorder
将{props.children}
呈如今
this.props.children
是谁。好比下面这样:
// News.js render() { return ( <div className={style.container}> {this.props.children} </div> ); } // routers.js export function createRoutes() { return { path: '/', component: App, indexRoute: { component: Main }, childRoutes: [ { path: ':channel', component: NewsList, } ], }; }
这里News组件的子组件就是NewsList。
虽然不常见,可是有时候你可能在组件里须要多个'hole', 在这种状况下,你可能想出本身的习惯,而不是使用children
:
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 /> } /> ); }
有时咱们将组件视为其余组件的"特殊状况"。举例来讲,咱们能够说WelcomeDialog
是Dialog
的一种特殊状况。
在React中,这一般由组合来实现,其中一个更"特定"的组件呈现出更"通用的组件", 而且使用props
来配置它。
function Dialog(props) { return ( <FancyBorder color="blue"> <h1 className="Dialog-title"> {props.title} </h1> <p className="Dialog-title"> {props.message} </p> </FancyBorder> ); } function WelcomeDialog() { return ( <Dialog title="Welcome" message="Thank you for visiting our spacecraft!" /> ); }
组合对于定义为类的组件一样适用。
function Dialog(props) { return ( <FancyBorder color="blue"> <h1 className="Dialog-title"> {props.title} </h1> <p className="Dialog-message"> {props.messgae} </p> {props.children} </FancyBorder> ); } class SignUpDialog extends React.Component { constructor(props) { super(props); this.handleChange = this.handleChange.bind(this); this.handleSignUp = this.handleSignUp.bind(this); this.state = {login: ''}; } handleChange(e) { this.setState({ login: e.target.value, }); } handleSignUp() { alert(`Welcome aboard, ${this.state.login}!`); } render() { return ( <Dialog title="Mars Exploration Program" message="How should we refer to you?"> <input value={this.state.login} onChange={this.handleChange} /> <button onClick={this.handleSignUp}> Sign Me Up! </button> </Dialog> ); } }
在Facebook, 咱们在数千计的组件中,尚未发现任何一种状况值得咱们推荐使用继承。使用Props和composition就已经很完美了。
使用单一任务原则,也就是说,一个组件理想上只作一件事情。
使用mock数据构架一个没有交互的静态版本。由于构建一个静态的版本,须要大量的typing
和不须要思考太多,而构建一个交互性的版本须要大量的思考,而不须要大量的typing
。
若是你很熟悉state
的概念,那么就不要使用state
来构建静态的版本, state
只是为了交互而保留的。
你既能够自下向上进行构建,也能够自上向下构建。在简单的例子中,一般更容易自上而下;而在较大的例子中,自下而上一般更容易一些,而且也更容易写测试。
要使你的应用能够交互,你须要可以触发底层数据模型的更改, State
让这一切变得很容易。
为了正确的构建你的app,首先你须要思考你的app须要的最小的可变的state集。这里很关键的是DRY: Don't repeat yourself。找出你的app须要的state集的最小表示,并计算出你所须要的其余需求。举例来讲,若是你要构建一个Todo List
, 只须要维持一个todo items
的数组,不须要为数量单独保持一个state的变量。当你想要渲染todo的数量时,只须要取todos数组的长度就能够了。
如何区分是数据是state仍是props,只须要问下面这三个问题:
当咱们肯定app的最小的state集后。下一步,咱们须要肯定是哪个组件拥有state。
记住: React是单向数据流,可能不能当即清楚哪一个组件拥有哪一个state。这对于新手来讲也是最大的挑战,所以根据下面这些步骤来解决这个问题:
对于你的应用中的每一个state:
find a common owner component
(单个组件,它是全部须要那个state的组件的父级组件)。子组件经过props调用父级组件 传递过来的方法(回调)来改变父级的state。