React 是一个用于构建用户界面的 JavaScript 库
1.点击进入网站安装Node.js(为了运行 create-react-app)
安装Node.js
2.在终端打开Node.js的根目录并且运行
npx create-react-app moz-todo-react
这句命令创建了一个名为 moz-todo-react 的文件夹, 并在此文件夹里做了如下工作:
3.处理完成之后,你可以 cd 到 moz-todo-react 文件夹下,然后键入 npm start 命令并回车,先前由 create-react-app 创建的脚本会启动一个地服务 localhost:3000,并打开你的默认浏览器来访问这个服务。成功启动浏览器的话,你的浏览器上会显示如下画面:
接下来,我会用一个项目来介绍 React的核心概念,在这个过程中可以对React的用法有更深的理解,不过前提是你必须有Web的基础:HTML、CSS、JavaScript
在设计一个React项目之前,我们需要明确这个项目由哪几部分组成,换句话说,组成这个项目的是哪些组件?这些组件的功能是什么?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
在这个系统中,我们要实现的功能是:在搜索栏键入体育用品的名称,在其下方显示出这个体育用品的名称和价格,其次,在搜索栏下方有一个checkbox,当选中的时候在下方只会显示已经储存在仓库中的体育用品,而没有储存在仓库中的则不显示。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
接下来,你将会学到React的几个核心概念:
元素渲染、条件渲染、事件处理、Props和states、列表和key
React提供了组件化的设计方式,因此,我们需要将实现的功能进行组件化,将每部分看作是一个组件,并对这一系列的组件进行设计和层次分级。
我们将要实现下图这样一个体育用品仓库系统
将各个组件进行标示:
FilterableProductTable (橙色): 是整个示例应用的整体
SearchBar (蓝色): 接受所有的用户输入
ProductTable (绿色): 展示数据内容并根据用户输入筛选结果
ProductCategoryRow (天蓝色): 为每一个产品类别展示标题
ProductRow (红色): 每一行展示一个产品
根据功能进行层级划分:
这部分涉及到的知识点有:元素渲染、条件渲染、事件处理、Props。
你可以自上而下或者自下而上构建应用:自上而下意味着首先编写层级较高的组件(比如 FilterableProductTable),自下而上意味着从最基本的组件开始编写(比如 ProductRow)。当你的应用比较简单时,使用自上而下的方式更方便;对于较为大型的项目来说,自下而上地构建,并同时为低层组件编写测试是更加简单的方式。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
我们需要搭建出如上图所示的系统,在这一步中,我们只需要构建出这个系统的外观暂时先不需要理会用户交互的部分。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
<!-- React核心库 注意:这里引入的顺序一定要是核心库最先引入-->
<script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
<!-- React-dom 用于Recat操作DOM -->
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
<!-- 引入bable,将jsx转为(翻译为)js -->
</head>
<body>
<div id='root'></div>
</body>
</html>
我们将组件拆分来看:(这也是我认为React的优势之一,选择它作为前端开发的框架,利用它组件化的特色,非常便与开发者的调试和维护。
组件ProductRow:每一行展示一个产品
class ProductRow extends React.Component{
render(){
const product = this.props.product;
const name = product.stocked?product.name:<span style={{color:'red'}}>{product.name}</span>;
return(
<tr>
<td>{name}</td>
<td>{product.price}</td>
</tr>
);
}
}
组件ProductCategoryRow:为每一个产品类别展示标题
class ProductCategoryRow extends React.Component{
render(){
const category = this.props.category;
return(
<tr>
<th>{category}</th>
</tr>
)
}
}
组件ProductTable:展示数据内容并根据用户输入筛选结果
class ProductTable extends React.Component{
render(){
const rows = [];
let lastcategoty = null;
this.props.products.forEach((product) => {
if(product.category !==lastcategoty)
{
rows.push(<ProductCategoryRow category={product.category} key={product.category}/>);
}
rows.push(<ProductRow product={product} key={product.name}/>);
lastcategoty = product.category;
})
return(
<table>
<thead>
<tr>
<th >Name</th> <th>Price</th>
</tr>
</thead>
<tbody>{rows}</tbody>
</table>
)
}
}
组件SearchBar :接受所有的用户输入
class SearchBar extends React.Component{
render(){
return(
<form>
<input type='text' placeholder = " Enter to search..."/>
<p>
<input type='checkbox'/>
Only show products in stock
</p>
</form>
)
}
}
组件FilterableProductTable:是整个示例应用的整体(父组件)
父组件负责传入props参数,这时props像河流一样从上往下流,其它子组件如同它的支流,一起朝着同一方向流。
class FilterableProductTable extends React.Component{
render(){
return(
<div>
<SearchBar/>
<ProductTable products={this.props.products}/>
</div>
);
}
}
完整代码:
<script type='text/babel'>
class ProductRow extends React.Component{
render(){
const product = this.props.product;
const name = product.stocked?product.name:<span style={{color:'red'}}>{product.name}</span>;
return(
<tr>
<td>{name}</td>
<td>{product.price}</td>
</tr>
);
}
}
class ProductCategoryRow extends React.Component{
render(){
const category = this.props.category;
return(
<tr>
<th>{category}</th>
</tr>
)
}
}
class ProductTable extends React.Component{
render(){
const rows = [];
let lastcategoty = null;
this.props.products.forEach((product) => {
if(product.category !==lastcategoty)
{
rows.push(<ProductCategoryRow category={product.category} key={product.category}/>);
}
rows.push(<ProductRow product={product} key={product.name}/>);
lastcategoty = product.category;
})
return(
<table>
<thead>
<tr>
<th >Name</th> <th>Price</th>
</tr>
</thead>
<tbody>{rows}</tbody>
</table>
)
}
}
class SearchBar extends React.Component{
render(){
return(
<form>
<input type='text' placeholder = " Enter to search..."/>
<p>
<input type='checkbox'/>
Only show products in stock
</p>
</form>
)
}
}
class FilterableProductTable extends React.Component{
render(){
return(
<div>
<SearchBar/>
<ProductTable products={this.props.products}/>
</div>
);
}
}
const PRODUCTS =[
{category: 'Sporting Goods', price: '$49.99', stocked: true, name: 'Football'},
{category: 'Sporting Goods', price: '$9.99', stocked: true, name: 'Baseball'},
{category: 'Sporting Goods', price: '$29.99', stocked: false, name: 'Basketball'},
{category: 'Electronics', price: '$99.99', stocked: true, name: 'iPod Touch'},
{category: 'Electronics', price: '$399.99', stocked: false, name: 'iPhone 5'},
{category: 'Electronics', price: '$199.99', stocked: true, name: 'Nexus 7'}
];
ReactDOM.render(
<FilterableProductTable products={PRODUCTS}/>,
document.getElementById('root')//渲染时传入我们预设好的体育用品项目的信息。
);
</script>
这一步设计到的知识点比较多,同时也是React中的重难点之一。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
想要使我们的UI具备交互功能,需要有触发基础数据模型改变的能力。
React通过state来实现这个任务(还不了解state的同学请转到另一篇文章或自行搜索学习)
完整代码:
class ProductRow extends React.Component{
render(){
const product = this.props.product;
const name = product.stocked?product.name:<span style={{color:'red'}}>{product.name}</span>;
return(
<tr>
<td>{name}</td>
<td>{product.price}</td>
</tr>
);
}
}
class ProductCategoryRow extends React.Component{
render(){
const category = this.props.category;
return(
<tr>
<th colSpan='2'>{category}</th>
</tr>
)
}
}
class ProductTable extends React.Component{
render(){
const filtertext = this.props.filtertext;
const instockonly = this.props.instockonly;
const rows = [];
let lastcategoty = null;
this.props.products.forEach((product) => {
if(product.name.indexOf(filtertext) === -1){
return;
}//如果找不到该filtertext就return
if(instockonly&&!product.stocked){
return;
}//勾选项instockonly 但是没有stocked
if(product.category !==lastcategoty)
{
rows.push(<ProductCategoryRow category={product.category} key={product.category}/>);
}
rows.push(<ProductRow product={product} key={product.name}/>);
lastcategoty = product.category;
})
return(
<table>
<thead>
<tr>
<th >Name</th> <th>Price</th>
</tr>
</thead>
<tbody>{rows}</tbody>
</table>
)
}
}
class SearchBar extends React.Component{
render(){
const filtertext = this.props.filtertext;
const instockonly = this.props.instockonly;
return(
<form>
<input
type='text'
placeholder = " Enter to search..."
value={filtertext}
/>
<p>
<input type='checkbox' checked={instockonly}/>
{' Only show products in stock '}
</p>
</form>
)
}
}
class FilterableProductTable extends React.Component{
constructor(props){
super(props);
this.state = {
filtertext:'',
instockonly:false
};
}
render(){
return(
<div>
<SearchBar
filtertext={this.state.filtertext}
instockonly={this.state.instockonly}
/>
<ProductTable
products={this.props.products}
filtertext={this.state.filtertext}
instockonly={this.state.instockonly}
/>
</div>
);
}
}
const PRODUCTS =[
{category: 'Sporting Goods', price: '$49.99', stocked: true, name: 'Football'},
{category: 'Sporting Goods', price: '$9.99', stocked: true, name: 'Baseball'},
{category: 'Sporting Goods', price: '$29.99', stocked: false, name: 'Basketball'},
{category: 'Electronics', price: '$99.99', stocked: true, name: 'iPod Touch'},
{category: 'Electronics', price: '$399.99', stocked: false, name: 'iPhone 5'},
{category: 'Electronics', price: '$199.99', stocked: true, name: 'Nexus 7'}
];
ReactDOM.render(
<FilterableProductTable products={PRODUCTS}/>,
document.getElementById('root')
);
</script>
</body>
</html>
完整代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Sporting Goods</title>
<script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
</head>
<body>
<div id='root'></div>
<script type='text/babel'>
class ProductRow extends React.Component{
render(){
const product = this.props.product;
const name = product.stocked?product.name:<span style={{color:'red'}}>{product.name}</span>;
return(
<tr>
<td>{name}</td>
<td>{product.price}</td>
</tr>
);
}
}
class ProductCategoryRow extends React.Component{
render(){
const category = this.props.category;
return(
<tr>
<th colSpan='2'>{category}</th>
</tr>
)
}
}
class ProductTable extends React.Component{
render(){
const filtertext = this.props.filtertext;
const instockonly = this.props.instockonly;
const rows = [];
let lastcategoty = null;
this.props.products.forEach((product) => {
if(product.name.indexOf(filtertext) === -1){
return;
}//如果找不到该filtertext就return
if(instockonly&&!product.stocked){
return;
}//勾选项instockonly 但是没有stocked
if(product.category !==lastcategoty)
{
rows.push(<ProductCategoryRow category={product.category} key={product.category}/>);
}
rows.push(<ProductRow product={product} key={product.name}/>);
lastcategoty = product.category;
})
return(
<table>
<thead>
<tr>
<th >Name</th> <th>Price</th>
</tr>
</thead>
<tbody>{rows}</tbody>
</table>
)
}
}
class SearchBar extends React.Component{
constructor(props){
super(props);
this.handleFilterchange = this.handleFilterchange.bind(this);
this.handleInstockchange = this.handleInstockchange.bind(this);
}
handleFilterchange(e){
this.props.onFiltertextchange(e.target.value);
}
handleInstockchange(e){
this.props.onInStockChange(e.target.checked);
}
render(){
const filtertext = this.props.filtertext;
const instockonly = this.props.instockonly;
return(
<form>
<input
type='text'
placeholder = " Enter to search..."
value={this.props.filtertext}
onChange={this.handleFilterchange}
/>
<p>
<input type='checkbox'
checked={this.props.instockonly}
onChange={this.handleInstockchange}
/>
{' Only show products in stock '}
</p>
</form>
)
}
}
class FilterableProductTable extends React.Component{
constructor(props){
super(props);
this.state = {
filtertext:'',
instockonly:false
};
this.handleFilterchangeFun = this.handleFilterchangeFun.bind(this);
this.handleInstockchangeFun = this.handleInstockchangeFun.bind(this);
}
handleFilterchangeFun(filtertext){//修改state的值,这里的实参是e.target.value,这就是输入框中我们输入的值
this.setState(
{filtertext:filtertext}
);
}
handleInstockchangeFun(instockonly){
this.setState(
{instockonly:instockonly}
);
}
render(){
return(
<div>
<SearchBar
filtertext={this.state.filtertext}
instockonly={this.state.instockonly}
onFiltertextchange={this.handleFilterchangeFun}//这里容易混淆的地方:将该父组件的handleFilterchangeFun传入组件SearchBar中的onFiltertextchange
onInStockChange={this.handleInstockchangeFun}//接上句:组件SearchBar的onFiltertextchange由handleFilterchange(e)函数调用,对输入框进行监听
/>
<ProductTable
products={this.props.products}
filtertext={this.state.filtertext}
instockonly={this.state.instockonly}
/>
</div>
);
}
}
const PRODUCTS =[
{category: 'Sporting Goods', price: '$49.99', stocked: true, name: 'Football'},
{category: 'Sporting Goods', price: '$9.99', stocked: true, name: 'Baseball'},
{category: 'Sporting Goods', price: '$29.99', stocked: false, name: 'Basketball'},
{category: 'Electronics', price: '$99.99', stocked: true, name: 'iPod Touch'},
{category: 'Electronics', price: '$399.99', stocked: false, name: 'iPhone 5'},
{category: 'Electronics', price: '$199.99', stocked: true, name: 'Nexus 7'}
];
ReactDOM.render(
<FilterableProductTable products={PRODUCTS}/>,
document.getElementById('root')
);
</script>
</body>
</html>
希望这篇文档能够帮助你建立起构建 React 组件和应用的一般概念。
在编写React代码时要建立起清晰的思维——React的设计思维。
我也是刚学React,新手入门,如有错误请多多指教!这篇文章作为学习的成果总结,虽然有些地方总结的不是很详细,也有的知识点并没有详细介绍,因为网上都能够查得到(其实是因为懒得打字)
笔者现在是大一升大二的计算机科班学生,希望随着今后的学习能够为大家带来更优质的文章!
注:以上项目素材来自React官方网站