开始学习react,先从react官网的案例开始,,学习react中的组件,数据传递,还有JSX
项目地址
- 官网案例地址 - reactjs.org/community/e…
- Counter App(本文案例) - github.com/arnab-datta…
预备知识
- 必须要有render
- 外层仅有一个div
- {} 内可以放任何JavaScript代码,如表达式,函数等
- class 用 className
- label的for属性 用 htmlFor
- 所有的React模块都要引用React(import React from 'react'),是为了将代码中的JSX转为React.createElement()
- React 组件使用帕斯卡命名法,又称为"大驼峰式命名法",如“HelloWorld”
- React 的组件要用export导出,这样其他文件可以使用
- prop 是任何传入 React 组件的数据
- 通过把变量放在大括号中,您可以读取 JSX 的变量,如
{so}
react里的 index.js 是怎么跟 index.html 结合起来的?
-
你可以在项目下运行npm run eject,被隐藏的配置文件就会暴露到项目根路径下。把请求转发到index.html原因是,你执行npm run start时,启动的webpack-dev-server,会加载react-script项目config文件夹下的配置(paths.js),里面定义了请求的默认转发路径是public文件夹,自然就找到了public下的index.html。
案例分析
视图结构
文件结构
- src
- components - 组件
- counter.jsx
- counters.jsx
- navbar.jsx
- App.js - 组件集合
- index.css - 全局样式
- index.js - 文件入口
- components - 组件
代码细节
index.js
index.js主要作用
- 把App组件渲染到页面中,
- 使用的是ReactDOM,把App组件的内容,放到root里!
- 引入全局样式,这样组件就能使用了
App.js
import React, { Component } from "react"; // 必须要引入React!
import NavBar from "./components/navbar"; // 引入组件
import Counters from "./components/counters";
class App extends Component {
state = { // 定义数据集
counters: [
{ id: 1, value: 0 },
{ id: 2, value: 0 },
{ id: 3, value: 0 },
{ id: 4, value: 0 },
],
};
handleIncrement = (counter) => { // 父组件定义方法 - 增加数量,用于向子组件传递!
const counters = [...this.state.counters]; // 数据备份,不能直接修改state中的内容!
const index = counters.indexOf(counter);
// counters[index] = { ...counters[index] }; // 这一步是????
counters[index].value++;
this.setState({ counters }); // 使用set函数,视图重新 render 渲染
};
handleDecrement = (counter) => {
};
handleReset = () => {
};
handleDelete = (counterId) => {
};
handleRestart = () => {
};
render() { // render函数!
return ( // 返回一个jsx!外层仅一个div
<div className="main__wrap">
<main className="container">
<div className="card__box">
<NavBar
totalCounters={
this.state.counters.filter((c) => c.value > 0).length
}
/>
<Counters
counters={this.state.counters} // 这里的this指的是App,向子组件传递方法!
onReset={this.handleReset}
onIncrement={this.handleIncrement}
onDecrement={this.handleDecrement}
onDelete={this.handleDelete}
onRestart={this.handleRestart}
/>
</div>
</main>
</div>
);
}
}
export default App; // 导出App组件
counters.jsx
- 学习渲染组件的时候要加入key,vue的key要加冒号,react不用。。
- 使用map来循环渲染组件!
- key可以帮助react决定那些是要改变的,添加的,删除的,
- key应该放在map函数里面,这样保证每个都是key都是唯一的。。(推荐不要用index做key)
- 兄弟节点直接key要唯一,这个key不用全局唯一
- 如果map函数内容很多很多,就该抽离成组件了!
import React, { Component } from "react"; // 必须要引入React
import Counter from "./counter";
class Counters extends Component {
render() {
// 接收传入数据。
const { onReset, onIncrement, onDelete, onDecrement, counters, onRestart } =
this.props;
return ( // 返回JSX
<div>
{/* 两个按钮 */}
<div className="row">
<div className="">
<button
className="btn btn-success m-2"
onClick={onReset} // 使用传入方法
disabled={counters.length === 0 ? "disabled" : ""}
>
<i className="fa fa-refresh" aria-hidden="true" /> // bootstrap的icon
</button>
<button
className="btn btn-primary m-2"
onClick={onRestart}
disabled={counters.length !== 0 ? "disabled" : ""}
>
<i className="fa fa-recycle" aria-hidden="true" />
</button>
</div>
</div>
{/* map遍历 */}
{counters.map((counter) => (
// 继续传递
<Counter
key={counter.id} // 在map里,保证key的唯一
counter={counter} // 继续向子组件传递
onIncrement={onIncrement}
onDecrement={onDecrement}
onDelete={onDelete}
/>
))}
</div>
);
}
}
export default Counters;
counter.jsx
// 为什么这里的React 不能去掉???
// 第一句代码引入了 React 库,这是为了将代码中的 JSX 语句转为React.createElement(),
// 所有的 React 模块都应该引入 React 模块,否则会抛错。
import React, { Component } from "react";
class Counter extends Component {
render() {
return (
<div>
<div className="row">
<div className="">
{/* 颜色变换 + 数值变换 */}
<span style={{ fontSize: 24 }} className={this.getBadgeClasses()}>
{this.formatCount()} // 通过方法的返回值来显示文字信息
</span>
</div>
<div className="">
<button
className="btn btn-secondary"
// 使用传入的方法(增加函数),这里传入的参数,用于在App.js中判断。。。。
onClick={() => this.props.onIncrement(this.props.counter)}
>
<i className="fa fa-plus-circle" aria-hidden="true" />
</button>
<button
className="btn btn-info m-2"
onClick={() => this.props.onDecrement(this.props.counter)}
disabled={this.props.counter.value === 0 ? "disabled" : ""}
>
<i className="fa fa-minus-circle" aria-hidden="true" />
</button>
<button
className="btn btn-danger"
// 这里的删除,使用的是filter过虑,把这个传入的id,筛掉
onClick={() => this.props.onDelete(this.props.counter.id)}
>
<i className="fa fa-trash-o" aria-hidden="true" />
</button>
</div>
</div>
</div>
);
}
// 返回class内容。。
getBadgeClasses = () => {
let classes = "badge m-2 badge-";
classes += this.props.counter.value === 0 ? "warning" : "primary";
return classes;
};
// 返回文字信息
formatCount = () => {
const { value } = this.props.counter;
return value === 0 ? "Zero" : value;
};
}
export default Counter;
navbar.jsx
发现还可以直接用函数接收变量。。
import React from "react";
// Stateless Functional Component
// 这里不用props,直接使用App.js传入的参数。。?????
const NavBar = ({ totalCounters }) => {
// 这里直接返回JSX就可以了。。不用render函数,如果基础component,必须要render函数
return (
<nav className="navbar navbar-light">
<div className="navbar-brand">
<i className="fa fa-shopping-cart fa-lg m-2" aria-hidden="true" />
<span
className="badge badge-pill badge-info m-2"
style={{ width: 50, fontSize: "24px" }}
>
{totalCounters}
</span>
Items
</div>
</nav>
);
};
--------
// 第二种。。
class NavBar extends Component {
render() {
return (
<nav className="navbar navbar-light">
<div className="navbar-brand">
<i className="fa fa-shopping-cart fa-lg m-2" aria-hidden="true" />
<span
className="badge badge-pill badge-info m-2"
style={{ width: 50, fontSize: "24px" }}
>
{this.props.totalCounters} // 使用props
</span>
Items
</div>
</nav>
);
}
}
export default NavBar;
总结
学习React的第一个案例
- react的组件划分也要靠视图来判断
- App.js中,定义好了方法,直接往下传递即可
- 多个数据用map来渲染,在map中使用key
- 改变state,要用setState
- 每个react模块,都要引用react,import react!
- {}里可以放数据,放方法,放任意Js表达式
- 组件的后缀是 jsx
- 继承component,一定要实现render方法。
- React组件命名,使用大驼峰
- 组件要用export导出
好的决心必须以行动来贯彻,没有行动,好的决心没有任何意义。