脚手架开发
- npx create-react-app {app-name}
- cd {app-name} -> npm run start
正确使用setState
- 不要直接修改 State,而是使用setState修改;
- Props和State 的更新可能是异步的,不要依赖他们的值来更新下一个状态。
// Wrong
this.setState({
counter: this.state.counter + this.props.increment,
});
// Correct
this.setState((state, props) => ({
counter: state.counter + props.increment
}));
- state 的更新会被合并;
- 数据是向下流动的, 你可以选择把它的 state 作为 props 向下传递到它的子组件中;
- 组件可以选择把它的 state 作为 props 向下传递到它的子组件中;
- react是“自上而下”或是“单向”的数据流。任何的 state 总是所属于特定的组件,而且从该 state 派生的任何数据或 UI 只能影响树中“低于”它们的组件。
- 需要基于当前的 state 来计算出新的值,那你应该传递一个函数,而不是一个对象,如this.setState((state) => {return {count: state.count + 1}});
事件注意事项
- 在 React 中另一个不同点是你不能通过返回 false 的方式阻止默认行为。你必须显式的使用 preventDefault;
- React 事件的命名采用小驼峰式(camelCase),而不是纯小写。
- 使用 JSX 语法时你需要传入一个函数作为事件处理函数,而不是一个字符串。
- 当你使用 ES6 class 语法定义一个组件的时候,通常的做法是将事件处理函数声明为 class 中的方法。
条件语句
- 在极少数情况下,你可能希望能隐藏组件,即使它已经被其他组件渲染。若要完成此操作,你可以让 render 方法直接返回 null,而不进行任何渲染。
状态提升
- 通常,多个组件需要反映相同的变化数据,这时我们建议将共享状态提升到最近的共同父组件中去;
- 例如A组件有B组件和C组件两个同级子组件,B组件显示摄氏度,C组件显示华氏度,需实现B组件和C组件的温度自动转换,
则可以将温度保存在A组件state的temperature中,通过B、C组件触发A组件props传入的方法改变temperature,再通过转换
函数处理temperature后分别再传入B、C组件中。
/**
*
* 在已有摄氏温度输入框的基础上,我们提供华氏度的输入框,并保持两个输入框的数据同步。
*
*/
/**
* 程序逻辑步骤;
* 【1】React 会调用 DOM 中 <input> 的 onChange 方法。在本实例中,它是 TemperatureInput 组件的 handleChange 方法。
* 【2】TemperatureInput 组件中的 handleChange 方法会调用 this.props.onTemperatureChange(),并传入新输入的值作为参数。其 props 诸如 onTemperatureChange 之类,均由父组件 Calculator 提供。
* 【3】起初渲染时,用于摄氏度输入的子组件 TemperatureInput 中的 onTemperatureChange 方法与 Calculator 组件中的 handleCelsiusChange 方法相同,而,用于华氏度输入的子组件 TemperatureInput 中的 onTemperatureChange 方法与 Calculator 组件中的 handleFahrenheitChange 方法相同。因此,无论哪个输入框被编辑都会调用 Calculator 组件中对应的方法。
* 【4】在这些方法内部,Calculator 组件通过使用新的输入值与当前输入框对应的温度计量单位来调用 this.setState() 进而请求 React 重新渲染自己本身。
* 【5】React 调用 Calculator 组件的 render 方法得到组件的 UI 呈现。温度转换在这时进行,两个输入框中的数值通过当前输入温度和其计量单位来重新计算获得。
* 【6】React 使用 Calculator 组件提供的新 props 分别调用两个 TemperatureInput 子组件的 render 方法来获取子组件的 UI 呈现。
* 【7】React 调用 BoilingVerdict 组件的 render 方法,并将摄氏温度值以组件 props 方式传入。
* 【8】React DOM 根据输入值匹配水是否沸腾,并将结果更新至 DOM。我们刚刚编辑的输入框接收其当前值,另一个输入框内容更新为转换后的温度值。
*/
// 接受 celsius 温度作为一个 prop,并据此打印出该温度是否足以将水煮沸的结果。
class BoilingVerdict extends React.Component {
constructor(props) {
super(props);
}
render() {
if (this.props.celsius >= 100) {
return <p>The water would boil.</p>
} else {
return <p>The water would not boil.</p>
}
}
}
// 渲染一个用于输入温度的 <input>,并将其值保存在 this.state.temperature 中。
// 另外, 它根据当前输入值渲染 BoilingVerdict 组件。
class Calculator extends React.Component {
constructor(props) {
super(props);
this.state = {temperature: '', scale: 'c'};
}
handleCelsiusChange(event, temperature) {
this.setState({scale: 'c', temperature});
}
handleFahrenheitChange(event, temperature) {
this.setState({scale: 'f', temperature});
}
render() {
const temperature = this.state.temperature;
const scale = this.state.scale;
const celsius = scale === 'f' ? tryConvert(temperature, toCelsius) : temperature;
const fahrenheit = scale === 'c' ? tryConvert(temperature, toFahrenheit) : temperature;
return (
<div>
<TemperatureInput scale="c" temperature={celsius} onTemperatureChange={(event, temperature) => this.handleCelsiusChange(event, temperature)} />
<TemperatureInput scale="f" temperature={fahrenheit} onTemperatureChange={(event, temperature) => this.handleFahrenheitChange(event, temperature)}/>
<BoilingVerdict celsius={parseFloat(celsius)} />
</div>
)
}
}
// 从 Calculator 组件中抽离出 TemperatureInput 组件,然后为其添加一个新的 scale prop,它可以是 "c" 或是 "f":
const scaleNames = {
c: 'Celsius',
f: 'Fahrenheit'
}
class TemperatureInput extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.state = { temperature: '' };
}
handleChange(e) {
// this.setState({
// temperature: e.target.value
// });
this.props.onTemperatureChange(e, e.target.value);
}
render() {
return (
<fieldset>
<legend>Enter temperature in {scaleNames[this.props.scale]}:</legend>
<input type="text" value={this.props.temperature} onChange={ this.handleChange }/>
</fieldset>
)
}
}
// 摄氏度和华氏度转换函数
function toCelsius(fahrenheit) {
return (fahrenheit - 32) * 5 / 9;
}
function toFahrenheit(celsius) {
return (celsius * 9 / 5) + 32;
}
// 根据转换函数求值,依据一个输入框的值计算出另一个输入框的值。
function tryConvert(temperature, convert) {
const input = parseFloat(temperature);
if (Number.isNaN(input)) {
return '';
}
const output = convert(input);
const rounded = Math.round(output * 1000) / 1000; // 保留三位小数并且四舍五入
return rounded.toString();
}
// 在 React 中,将多个组件中需要共享的 state 向上移动到它们的最近共同父组件中,便可实现共享 state。这就是所谓的“状态提升”
const element = <Calculator />;
const id = document.getElementById('example');
ReactDOM.render(element,id);
组合
-
可通过以下方式组合组件在页面显示:
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参数传递到其他组件。
-
推荐使用组合而非继承来实现组件间的代码重用。
设置state注意事项
从以下方案考试state合理性:
- 该数据是否是由父组件通过 props 传递而来的?如果是,那它应该不是 state。
- 该数据是否随时间的推移而保持不变?如果是,那它应该也不是 state。
- 你能否根据其他 state 或 props 计算出该数据的值?如果是,那它也不是 state。
从以下方面考虑state放在哪里:
对于应用中的每一个 state:
- 找到根据这个 state 进行渲染的所有组件。
- 找到他们的共同所有者(common owner)组件(在组件层级上高于所有需要该 state 的组件)。
- 该共同所有者组件或者比它层级更高的组件应该拥有该 state。
- 如果你找不到一个合适的位置来存放该 state,就可以直接创建一个新的组件来存放该 state,并将这一新组件置于高于共同所有者组件层级的位置。
网友评论