组件与Props
函数组件与class组件
接收: props 返回: react元素
function Welcome(props) {
return <h1> Hello, World </h1>;
}
ES6语法:
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
两者等价
渲染组件
DOM元素
const element = <div />
自定义元素
const elemet = <Welcom name="Sara" />
props
当 React 元素为用户自定义组件时,它会将 JSX 所接收的属性(attributes)以及子组件(children)转换为单个对象传递给组件,这个对象被称之为 “props”。
组件名称必须以大写字母开头
组合使用组件
这个App组件多次渲染了Welcome组件
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
const element = <Welcome name="Sara" />
function App() {
return (
<div>
<Welcome name="Sara" />
<Welcome name="Cahal" />
<Welcome name="Edite" />
</div>
);
}
ReactDOM.render(
<App />,
document.getElementById('root')
)
提取组件
将复杂的,复用性较高的组件提取成为简单,易用的组件。 命名: 推荐从组件自身角度命名,而不是依赖于调用组件的上下文命名。
Props只读性
纯函数: 不修改函数入参的的函数。 React要求像纯函数一样保护Props(单向数据流)。
生命周期 && state
生命周期方法
state使用
注意事项:
不可以直接修改state
使用setState修改:
this.setState({commit: 'Hello'});
State的更新可能是异步的
这是因为this.state 和 this.props 的更新可能是异步的.所以最好不要依赖它来更新下一个状态。
/* not good*/
this.setState({
counter: this.state.counter + this.props.increment,
});
解决方法: 通过回调函数来等待数据更新完成。
/** good */
this.setState((state, props) => ({ counter: state.counter + props.increment }));
State的更新会被合并
假如自定义了这个构造函数并且它拥有这些变量
constructor(props) {
super(props);
this.state = { posts: [], comments: [] };
}
可以分别更新state:
componentDidMount() {
fetchPosts().then(response => {
this.setState({
// 单独更新
posts: response.posts
});
});
fettchComments().then(response => {
this.setState({
// 单独更新
comments: response.comments
})
})
}
当更新posts时,state中的comments被保留,反之亦然。
State数据是独立且单向向下的
State是局部的,除了拥有并设置了它的组件,其他组件都无法访问。
<FormattedDate date={this.state.date} />
FormattedDate组件能接受date作为props,但是它不知道这个数据来自state。state只能影响本身及以下的组件
事件处理
·事件采用小驼峰命名法
·使用JSX语法时需要传入一个函数作为事件处理函数,而不是字符串
·必须显式使用e.preventDefault阻止默认行为
HTML:
<button onClick="handleClick()"></button>
React:
// 用{}把方法名包裹起来
<button onClick="{handleClick}"></button>
HTML:
<button onClick="console.log('click'); return false"></button>
React:
function ActionLink() {
function handleClick(e) {
// 阻止
e.preventDefault();
console.log('click');
}
return (
<a href="#" onClick={handleClick}>Click</a>
)
}
添加事件处理函数时,应该将处理函数添加为该class的方法
注意: 需要在初始渲染组件的时候就添加监听
向事件处理函数传参时,通常使用两种方法:
· 箭头函数 · bind
<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>
箭头函数中,e必须显式传递(放在括号里)。
条件渲染
function Greeting(props) {
const isLoggedIn = props.isLoggedIn;
if (isLoggedIn) {
return <UserGreeting />;
}
return <GuestGreeting />;
}
ReactDOM.render(
// Try changing to isLoggedIn={true}:
<Greeting isLoggedIn={false} />, document.getElementById('root'));
使用isLoggedIn判断是否登录,通过return不同的组件来完成条件渲染。
阻止渲染: return null // 这样并不会影响生命周期函数执行。
key
在循环向组件插入值时,需要给该组件一个key用来作为每个组件的唯一标识,当然,这个标识应当也是唯一的。类似Vue中的for循环也是需要key
key 提取组件
key应该放在就近的数组上下文才有意义,假如你提取了一个组件,那么,key应该保留在组件上,而不是在组件里面。
兄弟节点里的key应当时唯一的
key会传递信息给React,但是不会传递进组件,所以如果组件内需要使用到key值,就需要换个名字传禁区
状态提升
当多个组件有共用数据时,可以将组件的state提升到父组件中去,这样就可以共享组件的状态,以及数据的单向向下传递。
组合
假如不知道传入的子组件的内容是什么,那么可以使用props.children属性来渲染这未知的组件
这里有一个组件(未知组件的父组件):
function Father(props) {
return (
<div className="author">
// 内容将要渲染到这里
{props.children}
</div>
)
}
这里是父组件渲染出来的内容组件
function Boreder(props) {
return (
<Father>
// 这里是将要插入的子组件:
<h1>good</h1>
<p> you good</p>
</Father>
);
}
上面的Father组件内部的所有内容都将作为porps.children传到组件中去。
也可以不使用children:
function Mather(props) {
return (
<div>
<div className="author">{props.son}</div>
<div className="author">{props.doughter}</div>
</div>
);
}
function House(props) {
return (
<Mather son={<Sons />} doughter={<Dougther />} />
);
}
哪些值不应该放入state
· 不是从props传来的 · 不会变化的 · 根据其他state或props传递/计算而来的
state的位置:
应该高于共同所有组件层级的位置