赞
踩
使用create-react-app脚手架可以帮我们初始化一个项目demo
npx create-react-app my-app
项目结构:public/index.html是页面模板,src/index.js是入口JS文件
安装完成后,进入项目文件并启动
cd react-start
npm start
运行后会弹出react图标窗口。
下面将App.js文件修改一下:
import React, { Component } from 'react';
// import './App.css';
class App extends Component {
render() {
return <h1>Hello, React</h1>;
}
}
export default App;
此时react图标就会变成文字:Hello,React
在上面的代码中使用了JSX,全称是JavaScript XML。继续修改App.js:
const name = 'React';
const element = (
<div tabIndex="0" className="box">
<h1>Hello, {name}</h1>
<div className="name">
<span>xiaoqi</span>
</div>
</div>
);
class App extends Component {
render() {
return element;
}
}
element 就是一个JSX,可以看到它的特点:
元素是构成React应用的最小砖块。
创建一个元素element:
const element = (
<div className="box">
<h1>React 入门</h1>
<span> 元素是构成 React 应用的最小砖块。</span>
</div>
);
将这个渲染到DOM根结点,需要使用ReactDOM.render()方法:
ReactDOM.render(element, document.getElementById('root'));
修改index.js文件:
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
// import App from './App';
// import * as serviceWorker from './serviceWorker';
const element = (
<div className="box">
<h1>React 入门</h1>
<span> 元素是构成 React 应用的最小砖块。</span>
</div>
);
ReactDOM.render(element, document.getElementById('root'));
组件分为两种:Class组件和Function组件。
大多数的React应用都由很多小组件组成,将所有的小组件都添加到App主组件中,最后将App主组件渲染到入口js文件index.js中。
创建一个Class组件只需要创建一个class类,并且继承React.Component,在render()方法中return出JSX模板。
接下里在scr文件夹中创建一个Table.js文件:
// Table组件 import React, { Component } from 'react'; class Table extends Component { render() { return ( <table> <thead> <tr> <th>Name</th> <th>Job</th> </tr> </thead> <tbody> <tr> <td>Charlie</td> <td>Janitor</td> </tr> <tr> <td>Mac</td> <td>Bouncer</td> </tr> <tr> <td>Dee</td> <td>Aspiring actress</td> </tr> </table> ); } } export default Table;
将其添加到App主组件中:
class App extends Component {
render() {
return (
<div className="app">
<h1> Hello, React</h1>
<Table />
</div>
);
}
}
上面的Table组件可以拆分为两个子组件:TableHeader和TableBody,这两个组件可以使用Function组件来创建:
// TableHeader组件 const TableHeader = () => { return ( <thead> <tr> <th>Name</th> <th>Job</th> </tr> </thead> ); }; // TableBody 组件 const TableBody = () => { return ( <tbody> <tr> <td>Charlie</td> <td>Janitor</td> </tr> <tr> <td>Mac</td> <td>Bouncer</td> </tr> <tr> <td>Dee</td> <td>Aspiring actress</td> </tr> </tbody> ); }; class Table extends Component { render() { return ( <table> <TableHeader /> <TableBody /> </table> ); } }
比较一下Function组件和Class组件:
Function组件:
const functionComponent = () => {
return <div> Example</div>
}
Class组件:
class ClassComponent entends React.Component {
render() {
return <div> Example</div>
}
}
React使用props传递数据。
如果表格的数据很多,那么上面的TableBody组件会显得很臃肿。因此可以将tbody中要输出的数据提取出来,通过props的方式进行传递。
修改App.js文件:在App组件中生命数据charaters,表示中要输出的数据。在子组件Table上添加属性名称和数据。
class App extends Component { render() { // 提取数据 const characters = [ { name: 'Charlie', job: 'Janitor', }, { name: 'Mac', job: 'Bouncer', }, { name: 'Dee', job: 'Aspring actress', }, ]; return ( <div className="app"> <h1> Hello, React</h1> <Table characterData={characters} /> </div> ); } }
然后在子组件Table中通过this.props.属性名
来获取父组件中传递的数据:
class Table extends Component {
render() {
const { characterData } = this.props;
return (
<table>
<TableHeader />
<TableBody characterData={characterData} />
</table>
);
}
}
这里的 const { characterData } = this.props 相当于 const characterData = this.props.characterData,这里只是es6的写法。
继续将数据传递给TableBody组件。由于TableBody是一个function组件,所以其接收数据的方式跟class组件是不一样的。其使用props的方法直接是将props作为参数名传递给function组件:
// TableBody 组件
const TableBody = (props) => {
const rows = props.characterData.map((item, index) => {
return (
<tr key={index}>
<td>{item.name}</td>
<td>{item.job}</td>
</tr>
);
});
return <tbody>{rows}</tbody>;
};
这里给每个表行都添加了一个key,事实上react创建列表时必须通过key来识别列表的每一项。
props是单向传递,并且是只读的。如果想改变数据的状态,可以使用state,与props不同的是,state可变,但是state是class组件私有的对象。
修改state不能直接修改,要使用this.setState()
方法来改变。
下面实现一个功能:在每行后面添加一个删除按钮,点击之后可以删除该行。继续修改App.js:
class App extends Component { state = { characters: [ { name: 'Charlie', job: 'Janitor', }, { name: 'Mac', job: 'Bouncer', }, { name: 'Dee', job: 'Aspring actress', }, ], }; // 箭头函数解决 class中this不绑定的问题 removeCharacter = (i) => { this.setState({ characters: this.state.characters.filter((item, index) => { return i !== index; }), }); }; render() { // 提取数据 return ( <div className="app"> <h1> Hello, React</h1> <Table characterData={this.state.characters} removeCharacter={this.removeCharacter} /> </div> ); } }
通过state来传递数据,并通过setState方法来改变数据。
这里将removeCharacter传递给Table组件后,还需要继续传给TableBody组件,并且还需要在TableBody组件中给每行添加一个按钮,点击之后触发此函数:
// Table组件 import React, { Component } from 'react'; // TableHeader组件 const TableHeader = () => { return ( <thead> <tr> <th>Name</th> <th>Job</th> </tr> </thead> ); }; // TableBody 组件 const TableBody = (props) => { const rows = props.characterData.map((item, index) => { return ( <tr key={index}> <td>{item.name}</td> <td>{item.job}</td> <td> <button onClick={() => props.removeCharacter(index)}>Delete</button> </td> </tr> ); }); return <tbody>{rows}</tbody>; }; class Table extends Component { render() { const { characterData, removeCharacter } = this.props; return ( <table> <TableHeader /> <TableBody characterData={characterData} removeCharacter={removeCharacter} /> </table> ); } }
注意:State的更新可能是异步的,React可能会把多个setState()调用合并成一个调用。
props与state的区别
React中的事件处理和DOM元素的很相似,但在语法上有不同:
在上面的例子中实现了将数据存储在state状态中,并且可以从状态中删除任何数据。下面通过事件处理方式说明如何添加数据。
首先创建一个表单Form.js,将表单的初始状态设置为带有空属性的对象,并且将初始状态赋给this.state:
import React, { Component } from 'react' class Form extends Component { initialState = { name: '', job: '', } state = this.initialState handleChange = (event) => { const { name, value } = event.target; this.setState({ [name]: value, }); } render() { const { name, job } = this.state; // 初始化时为空 return ( <form> <label htmlFor="name">name</label> <input type="text" name="name" id="name" value={name} onChange={this.handleChange} /> <label htmlFor="job">job</label> <input type="text" name="job" id="job" value={job} onChange={this.handleChange} /> </form> ); } } export default Form;
通过onChange事件监听输入框的变化,将handleChange方法绑定到该事件上。一旦有输入,则触发执行handleChange方法,在该方法中由setState实时更新输入框的内容。
注意:在class组件中,class的方法默认不会绑定this,所以要谨慎JSX回调函数中的this。
例如上面的例子中,如果忘记绑定this,直接将this.handleChange传入onChange,调用函数时this将会是undefined。
绑定this的方式:
(1)class的方法上使用箭头函数,如上例所示,handleChange = (event) => {…} 。
(2)显式绑定:
// 直接在传入时进行绑定
onChange={this.handleChange.bind(this)}
接下来提交表单,在输入框后面增加一个提交按钮,并将onClick事件与submitForm函数进行绑定:
// 提交表单 submitForm = () => { this.props.handleSubmit(this.state); // 添加后清空state: this.setState(this.initialState); } render() { ... return ( <form> ... <input type = "button" value="submit" onClick={this.submitForm} /> </form> ); }
当点击提交按钮时触发subForm函数,该函数执行了从父组件app.js传递过来的handleSubmit函数:
handleSubmit = (character) => { // 添加数据 this.setState({ characters: [...this.state.characters, character] }) } render() { return ( <div className="app"> <h1>Hello, React</h1> <Table characterData={this.state.characters} removeCharacter={this.removeCharacter}> </Table> <Form handleSubmit={this.handleSubmit} /> </div> ); }
handleSubmit函数将输入的数据添加到原来的表单之中,就达到了添加数据的效果。
React中的条件渲染和javascript中一样,可以使用运算符if或者条件运算。
下面实现一个登陆退出按钮,根据不同的状态实现不同的效果。为了方便,还是在上面的项目基础上实现。
添加一个Login.js文件:
import React, { Component } from 'react' // 登录 const LoginButton = (props) => { return <button onClick={props.click}>Login</button>; } // 注销 const LogoutButton = (props) => { return <button onClick={props.click}>Logout</button> } // 登录描述 const LoginGreeting = () => { return <span>Welcome </span>; }; // 注销描述 const LogoutGreeting = () => { return <span>Please sign up</span>; }; const Greeting = (props) => { const {isLoggedIn} = props; return <div>{isLoggedIn ? <LoginGreeting/> : <LogoutGreeting/>}</div> } class LoginControl extends Component { // 初始状态 state = { isLoggedIn: false, }; handleLoginClick = () => { this.setState({ isLoggedIn: true, }); }; handleLogoutClick = () => { this.setState({ isLoggedIn: false, }); }; render() { const isLoggedIn = this.state.isLoggedIn; let button; // 通过if语句来进行条件渲染 if (isLoggedIn) { button = <LogoutButton click={this.handleLogoutClick}></LogoutButton> } else { button = <LoginButton click={this.handleLoginClick}></LoginButton> } return ( <div> <Greeting isLoggedIn = {isLoggedIn} /> {button} </div> ); } } export default LoginControl
然后修改app.js,在表单后添加登录按钮和greeting:
<LoginControl />
就可以实现按照是否登录条件来显示登录按钮状态了:
在上面的例子中TableBody组件中使用了tr
和td
元素,可以看到,每个tr
中都有一个特殊的属性key
,这个key
是必须的。
key
帮助React识别哪些元素发生了改变,比如删除或添加。key
就可以作为这个改变的元素的唯一标识,因此key
在列表中应该是独一无二的。通常使用id来作为元素的key
,如果元素没有确定的id
时,可以使用元素索引index
作为key
。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。