查看更详细教程,请阅读 React官方文档
一、搭建环境
1、方式1:在网站中直接引入使用
<script src="//www.w3cschool.cn/statics/assets/react/react.min.js"></script>
<script src="//www.w3cschool.cn/statics/assets/react/react-dom.min.js"></script>
<script src="//www.w3cschool.cn/statics/assets/react/babel.min.js"></script>
实现 hello world !
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>react</title>
<script src="//www.w3cschool.cn/statics/assets/react/react.min.js"></script>
<script src="//www.w3cschool.cn/statics/assets/react/react-dom.min.js"></script>
<script src="//www.w3cschool.cn/statics/assets/react/babel.min.js"></script>
</head>
<body>
<div id="app"></div>
<script type="text/babel">
ReactDOM.render(
<h1>Hello, world!</h1>,
document.getElementById('app')
);
</script>
</body>
</html>
注意:script标签内type属性需要填写为 type = "text/babel";
2、方式2:使用脚手架搭建本地环境
npm install create-react-app -g // 安装react-react-app
create-react-app react_test // 创建项目,项目名:react_test
cd react_test // 进入项目根目录下
npm start // 启动react项目,启动成功会自动在浏览器上启动
默认项目结构
react_test/
README.md
node_modules/ // node环境项目依赖
package.json // 项目配置依赖文件
public/ // 公共静态资源文件夹
index.html // 项目入口模板文件
favicon.ico
src/
App.css
App.js // 默认app主入口
App.test.js
index.css
index.js // 项目渲染主文件
logo.svg
二、React 基础
1、元素
元素是构成 React 应用的最小砖块,如下是一个元素
const element = <h1>hello world!</h1>
元素渲染
const element = <h1>Hello, world</h1>;
ReactDOM.render(element, document.getElementById('root'));
2、组件
定义组件(函数组件)
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
还可以使用es6的class语法进行定义组件(等效于普通函数组件)
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
渲染组件
function App(){
return (
<div>
<Welcome name="小书包" />
<Welcome name="小书包2" />
<Welcome name="小书包3" />
</div>
)
}
ReactDOM.render(App, document.getElementById('root'));
- 组件可以多次复用
- 组件上可以通过属性名传递参数,组件内通过props参数接收,props是一个对象。
3、state
state一般用于组件内的数据展示,可以通过改变state以改变组件的状态。
下面是一个显示当前时间的组件:
class Clock extends React.Component {
constructor(props) {
super(props)
this.state = {
date: new Date(),
}
}
render() {
return (
<div>
<h2>当前时间:{this.state.date.toLocaleTimeString()}</h2>
</div>
);
}
}
我们可以在构造方法中定义我们要使用的state,然后可以在组件中使用。注意:在每一个组件中调用一次super是必须的,才能在组件中获得react的实例方法并使用。
此例子显示了当前当前渲染的时间,但是不会更新当前时间,下面是一个会自动更新时间的例子:
class Clock extends React.Component {
constructor(props) {
super(props)
this.state = {
date: new Date(),
}
}
componentDidMount() { // 组件生命周期:组件加载完成后调用
setInterval(()=>{
this.setState({date:new Date()})
},1000)
}
render() {
return (
<div>
<h2>当前时间:{this.state.date.toLocaleTimeString()}</h2>
</div>
);
}
}
我们可以通过this.setState去更改state,实现实时更新state状态。react会根据state中的数据变化,为对应的部分进行渲染更新。
注意:state仅能通过this.setState方法进行更新state,不能直接通过this.state进行更新。
state的数据是向下流的:
父组件的state可以给子组件使用,但是子组件的state不能反过来给父组件使用。
4、事件
在标签或组件上绑定事件:
<button onClick={this.handleClick}>点击</button>
其中handleClick是组件内的一个方法。值得注意的是:以前我们阻止一个事件的默认行为可以通过 return false实现,在react中,我们需要通过在方事件法中调用e.preventDefault()
function handleClick(e) {
e.preventDefault();
}
下面是一个开关状态切换的示例:
class Toggle extends React.Component {
constructor(){
super();
this.state = {
open: true
}
this.toggle = this.toggle.bind(this) // 一般我们都会将toggle方法绑定到this实例
}
toggle(){
this.setState({
open: !this.state.open
})
}
render(){
return (
<button onClick={this.toggle}>{this.state.open ? '开' : '关'}</button>
)
}
}
注意:我们需要将方法绑定到实例对象上,否则无法实例的方法与数据。
或者我们还可以在标签上绑定事件时使用一个箭头函数。
<button onClick={() => this.toggle()}>{this.state.open ? '开' : '关'}</button>
事件传参:
<button onClick={() => this.toggle("这是传递的参数")}>{this.state.open ? '开' : '关'}</button>
//以下等值
<button onClick={this.toggle.bind(this,"这是传递的参数")}>{this.state.open ? '开' : '关'}</button>
5、条件渲染
在函数组件内条件判断输出:
function Condition(){
if(true){
return <h1>条件为真时输出我!</h1>
}
return <h1>条件为假时输出我!</h1>
}
也可以通过jsx中判断输出:
render(){
return(
{
2 > 1 && <h1>前面表达式成立才会有我的输出哦</h1>
}
)
}
&&与运算只要两者都为真,必定会返回第二者
还可以通过三元运算输出:
render(){
return(
{
2 > 1 ? <h1>条件成立</h1> : <h1>条件不成立</h1>
}
)
}
6、列表渲染
我们可以在函数组件中使用 javascript 的循环逻辑进行组装组件,示例如下:
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
<li>{number}</li>
);
return (
<ul>{listItems}</ul>
);
}
const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
<NumberList numbers={numbers} />,
document.getElementById('root')
);
上面这段代码运行会提示 a key should be provided for list items,虽然不会导致运行错误,但是可能会性能较差。
我们应该为列表中的每一项添加一个唯一的 key,一般可以使用每一项的id值作为key。
const listItems = numbers.map((number) =>
<li key={number.toString()}>
{number}
</li>
);
列表渲染我们还可以在 JSX 中实现。
function NumberList(props) {
const numbers = props.numbers;
return (
<ul>
{
numbers.map((number) =>
<ListItem key={number.toString()} value={number} />
)
}
</ul>
);
}
7、表单
在react中,表单元素使用的是受控组件开发,下面看看什么是受控组件。
受控组件:
表单元素(如:input、textarea、select)是组件内的state进行控制显示,而不是由元素自身进行控制。对元素进行事件监听获得输入内容再传递给state进行保存,而实现state控制元素的内容显示。示例如下:
class Form extends React.Component {
constructor(){
super()
this.state = {
name: '', // 给定的name值
}
this.nameInput = this.nameInput.bind(this)
}
nameInput(e){
this.setState({
name: e.target.value
})
}
render(){
return (
<input type="text" value={this.state.name} onChange={this.nameInput} />
)
}
}
textarea 标签:
在html中给textarea指定默认值如下:
<textarea>这是默认值</textarea>
但是在JSX中,指定默认值是通过value属性,监听用户输入 onChange。与input十分相似。
<textarea value={this.state.value} onChange={this.nameInput} />
select 标签:
在html中指定选中项是这样的:
爱好:
<select>
<option value="1">踢足球</option>
<option checked value="2">唱歌</option>
<option value="3">跳舞</option>
</select>
在 JSX 中,不使用checked,依然使用 value 绑定选中项,onChange 监听选择,示例如下:
爱好:
<select value={this.state.hobby} onChange={this.hobbyChange}>
<option value="1">踢足球</option>
<option value="2">唱歌</option>
<option value="3">跳舞</option>
</select>
select 多选可以这样做:
添加属性multiple={true},value接受一个数组
<select multiple={true} value={['1', '2']} onChange={this.hobbyChange}>
<option value="1">踢足球</option>
<option value="2">唱歌</option>
<option value="3">跳舞</option>
</select>
这个例子将会默认选中第一、二项,
处理多个值输入:
可以给每一个input添加一个name属性,并给定值。可以通过一个方法对多个输入进行赋值:
class Form extends React.Component {
constructor(){
super()
this.state = {
name: '', // 姓名
remark: '', // 备注
}
this.valueInput = this.valueInput.bind(this)
}
valueInput(e){
let value = e.target.value;
let name = e.target.name;
this.setState({
[name]: value
})
}
render(){
return (
<form>
<input name="name" type="text" value={this.state.name} onChange={this.valueInput} />
<textarea name="remark" value={this.state.remark} onChange={this.valueInput} />
</form>
)
}
}
8、状态提升
当多个组件需要使用到同一数据时,我们应该将这一状态提取到公共的父组件去,我们知道state的数据是向下流的。这成为react的状态提升。
9、组合
有时候,我们需要在另一个组件中插入我们需要的内容,我们应该如何实现呢,react已经为我们提供了非常强大的组合功能。
在组件元素中插入的内容将会传递到 props.children 中:
function Concat(props){
return (
<div>
<div>我的后面可以插入内容</div>
<div>{props.children}</div>
</div>
)
}
ReactDOM.render(
<Concat>
<h1>这是我插入的内容</h1>
</Concat>,
document.getElementById('root')
);
学过vue的可能会想起 “插槽slot”,在react中是没有插槽这个概念的。
插槽slot可以提供多个slot,即多个地方插入内容,那么react是如何实现的呢
我们知道props是可以传递任何类型的数据的,也包括标签元素,组件。所以我们可以将所需内容通过props传递,示例如下:
function Concat(props){
return (
<div>
<div>内容一:{props.content1}</div>
<div>内容二:{props.content2}</div>
</div>
)
}
ReactDOM.render(
<div>
<Concat content1={<h1>这是内容一</h1>} content2={<h1>这是内容二</h1>}></Concat>
</div>,
document.getElementById('root')
);
tips:因为react的组合功能足够强大,组件也可以是另一个组件的元素,所以react认为,不需要继承,在react 中没有继承概念。
三、React使用less
1、安装 less、less-loader
npm install less less-loader --save
2、释放配置
npm run eject
执行结束后,可以看到比原来多了以下目录(webpack配置文件)
3、配置
配置 config/webpack.config.js
在合适的位置添加以下规则
// style files regexes
const cssRegex = /\.css$/;
const cssModuleRegex = /\.module\.css$/;
const sassRegex = /\.(scss|sass)$/;
const sassModuleRegex = /\.module\.(scss|sass)$/;
const lessRegex = /\.less$/; // 新增
const lessModuleRegex = /\.module\.less$/; // 新增
找到以下配置,添加红框标识内容
找到以下内容,并在同层次位置添加以下内容
{
test: lessRegex,
exclude: lessModuleRegex,
use: getStyleLoaders(
{
importLoaders: 1,
sourceMap: isEnvProduction && shouldUseSourceMap,
},
'less-loader'
),
sideEffects: true,
},
{
test: lessModuleRegex,
use: getStyleLoaders(
{
importLoaders: 1,
sourceMap: isEnvProduction && shouldUseSourceMap,
module: true,
getLocalIdent: getCSSModuleLocalIdent
},
'less-loader'
),
},
到此配置已经完成,重启项目检查。
注:个人笔记,不作为标准答案,仅供参考,不喜勿喷!