一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第2天
文接上回,这几天一直在熟悉公司的代码
条件渲染
使用if运算符或条件运算符去创建元素当前的状态,然后React根据状态更新UI
如下面这两个组件
function UserGreeting(props) {
return <h1>Welcom back! </h1>;
}
funtion GuesGreeting(props) {
return <h1>Please sign up </h1>;
}
在创建一个Greeeting组件,他将会根据用户是否登陆决定显示哪一个组件
function Greeting(props) {
const isLoggedIn = props.isLoggedIn;
if(isLoggedIn) {
return <UserGreeting />;
}
return <GuestGreeting />;
}
ReactDOM.render(
<Greeting isLoggedIn={false} />
document.getElementById('root')
);
以上这个Grrrting组件将根据isLoggedIn的值显示那个组件。
阻止组件渲染
class Page extends React.component {
constructor(props) {
super(props);
this.state = {showWarning: true};
}
handleToggleClick = () => {
this.state(state => ({
showWarning: !state.showWarning
}));
}
function WarningBanner(props) {
if(!props.warn) {
return null;
}
return (
<div className = 'warning'>
Warning!
</div>
);
}
render() {
return (
<div>
<WarningBanner warn={this.state.showWarning} />
<button onClick={this.handleToggleClick}>
{this.state.showWarning ? 'Hide' : 'Show' }
<div>
);
}
}
ReactDOM.render(
<Page />
document.getElementById('root')
);
列表&Key
基础列表组件
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
<li>{number}</li>
);
return (
<ul>{lidtItems}</ul>
);
}
const numbers = [1, 2, 3, 4, 5];
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<NumberList numbers={numbers} />);
以上这段代码在运行时会提示警告,a key should be provied for list items
意思是当你创建一个元素时,必须包含一个特殊的key属性。下面,让我们给每个列表分配一个key属性来解决这个警告
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
<li key={number.toString()}>
{number}
</li>
);
return (
<ul>{listItems}</ul>
);
}
Key
key的作用是帮助React识别哪些元素改变了,比如添加或删除。因此你应该给数组中的每一个元素赋予一个确定的标识。
const numbers = [1, 2, 3, 4];
const listItems = number.map((number) =>
<li> key={number.toString()>
{number}
</li>
};
一个元素的key最好是这个元素独一无二的字符串, 通常我们使用数据中的id作为元素的key
如下所示:
const todoItems = todos.map((todo) =>
<li key={todo.key}>
{todo.text}
</li>
);
当元素没有确定id的时候,万不得已你可以使用元素索引index作为key
const todoItems = todos.map((todo, index) =>
<li key={index}>
{todo.text}
</li>
);
如果列表项目的顺序可能会发生变化,不建议使用索引来用作key值,因为这样会导致性能变差,还可能引起组件状态的问题。
用key提取组件
元素的key只有放在就近的上下文中才有意义。
比如说,你提取一个ListItem组件,应该把key保留在数组中的元素上,而不是放在ListItem组件中的
function ListItem(props) {
return <li>{props.value}</li>;
}
function NumberList(props) {
const number = props.numbers;
const listItems = numbers.map((number) =>
<ListItem key={number.toString()} value={number} />
);
return (
<ul>
{listItems}
</ul>
);
}
Key值在兄弟节点之间必须唯一
数组元素中使用的key值在其兄弟节点之间应该是独一无二的,然而,他们不需要是全局唯一的,当我们生成两个不同的数组时,可以使用相同的key值
function Blog(props) {
const sidebar = (
<ul>
{props.posts.map((post) =>
<li key={post.id}>
{post.title}
</li>
)}
</ul>
);
const content = props.posts.map((post) =>
<div key={post.id}>
<h3>{post.title}</h3>
<p>{post.content}</p>
</div>
);
return (
<div>
{sidebar}
<hr />
{content}
</div>
);
}
const posts = [
{id: 1, title: 'Hello World', content: 'Welcome to learning React!'},
{id: 2, title: 'Installation', content: 'You can install React from npm.'}
];
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Blog posts={posts} />);
key值会传递信息给React,但不会传递信息给组件。当组件中需要使用key的属性值时,可以用其他属性名显式传递这个值
const content = posts.map((post) =>
<Post
key={post.id}
id={post.id}
title={post.title} />
);
上述代码,Post组件可以读出props.id,但是不能读出props.key
表单
在React中,可变状态通常保存在组件的state属性中,并且只能通过setState()来更新。
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(event) {
this.setState({value: event.target.value});
}
handleSubmit(event) {
alert('提交的名字:' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
名字:
<input type="text" value={this.state.value} onChange={this.handleChange} />
</label>
<input type="submit" value="提交" />
</form>
);
}
}
在表单上设置了value属性,所以显示的值始终将为this.state.value,就使得React的state成为唯一的数据源。当handleChange执行后,更新相应的state,因此显示的值也进行更新
状态提升
下面这个示例中,创建一个用于计算水在给定的温度下是否会沸腾的温度计算器
const scaleName = {
c: 'Celsius',
f: 'Fahrenheit'
};
function toCelsius(fahrenheit) {
return (fahrenheit -32) * 5 / 9;
}
function toFahrenheit(celsius) {
return (celsius * 9 /5) + 32;
}
function tryConvert(temperature, convert) {
const input = parserFloat(temperature;
if(Number.isNaN(input)) {
return '';
}
const output = convert(input);
const rounded = Math.round(output *1000) / 1000;
return rounded.toString();
}
function BoilingVerdict(props) {
if(props.celsius >=100) {
return <p>The water would boil <p>
}
return <p>The water would not boil </p>;
}
class TemperatureInput extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.binf(this);
}
handleChange(e) {
this.props.onTemperatureChange(e.target.value);
}
render() {
const temperature = this.props.temperature;
const scale = this.props.scale;
return(
<filedest>
<legend>Enter temperature in {scaleNames[scale]}</legend>
<input value={temperature}
onChange={this.handleChange} />
<fieldest>
);
}
}
现在我们有了两个输入框,但是当你在其中一个输入温度时,另外一个输入框并不会更新。
在 React 中,将多个组件中需要共享的 state 向上移动到它们的最近共同父组件中,便可实现共享 state。这就是所谓的“状态提升”