安装官方脚手架:
sudo npm install -g create-react-app
创建项目:
npx create-react-app lesson1
进入项目目录:
cd lesson1
启动项目:
npm start
暴露配置项
npm run eject
安装sass(模块化)
npm install sass -D
React负责逻辑控制,数据->VDOM
ReactDom渲染实际DOM,VDOM->DOM
React使用JSX来描述UI
入口文件定义在webpack.config.js
先学一下JSX的语法
入口JS文件:
src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import logo from './logo.svg';
import "./index.css";
import styles from './index2.module.scss';
const name = 'xiaoming';
function formatName(user){
return user.firstName + " " + user.lastName;
}
const jsx = (
<div className={styles.app}>
jsx
<p>{name}</p>
<p>{formatName({firstName:'xiao',lastName:'ming'})}</p>
{
name? name: '登录'
}
<ul>
{
[0,1,2].map(item => {
return <li key={item}>
{item}
</li>
})
}
</ul>
<img className={styles.logo} src={logo}/>
</div>
)
//jsx里面用了React babel loader会把jsx的语法转成vdom render转化真实dom插入节点
ReactDOM.render(jsx, document.getElementById('root'));
src/index.css
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
"Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
monospace;
}
.logo{
width: 100px;
}
src/index2.module.scss
.app{
.logo{
width: 10px;
}
}
创建src/pages/ClassComponent.js组件
setState同步的三种方法
1.传入箭头函数,拿参数nextState里面的属性
2.setTimeout,setTimeout在react里面是同步的
3.原生事件操作,也是同步的
import React,{ Component } from 'react';
export default class ClassComponent extends Component {
constructor(props){
super(props);
this.state = {
date: new Date(),
counter: 0
};
}
//组件挂载后执行
componentDidMount(){
this.timer = setInterval(() => {
//每一次setState都会执行render
this.setState({
date: new Date()
});
},1000);
//方法三 原生事件
document.getElementById("test").addEventListener('click',()=>{
this.setState({
counter: this.state.counter + 1
});
})
}
//组件卸载之前完成
componentWillUnmount(){
if(this.timer){
clearInterval(this.timer);
}
}
setCounter = ()=>{
//setState是异步的 实现同步有几种办法?
//方法一 传函数 拿到一个nextState参数
// this.setState(nextState => {
// return {
// counter: nextState.counter + 1
// };
// });
// this.setState(nextState => {
// return {
// counter: nextState.counter + 2
// };
// });
// 方法二 setTimeout
// setTimeout(()=>{
// this.setState({
// counter: this.state.counter + 1
// });
// },0);
// this.setState({
// counter: this.state.counter + 1
// },
// () => {
// //callback可以马上拿到更新后的值
// })
}
render(){
const name = 'xiaoming';
const {date,counter} = this.state;
return (
<div>
<h1>ClassComponent</h1>
<p>{name}</p>
<div>{date.toLocaleTimeString()}</div>
<div id="test" onClick={this.setCounter}>{counter}</div>
</div>
)
}
};
在App.js引入
import React from 'react';
import ClassComponent from './pages/ClassComponent';
function App() {
return (
<div className="App">
<ClassComponent />
</div>
);
}
export default App;
在index.js引入
ReactDOM.render(<App/>, document.getElementById('root'));
函数代替组件
src/pages/FuncComponent.js
import React,{useState,useEffect} from 'react';
export default function FuncComponent() {
const [date,setDate] = useState(new Date());
const [counter,setCounter] = useState(0);
useEffect(() => {
//组件装载和更新都会走 可以控制依赖
const timer = setInterval(() => {
setDate(new Date());
},1000)
//回调就是卸载
return () => clearInterval(timer);
},[]);//第二个参数是依赖数组 空数组是没有依赖 只执行一次,[date]依赖date date更新就会执行
return (
<div>
<h1>FuncComponent</h1>
<p>{date.toLocaleTimeString()}</p>
</div>
)
};
app.js引入
import React from 'react';
import FuncComponent from './pages/FuncComponent';
function App() {
return (
<div className="App">
<FuncComponent />
</div>
);
}
export default App;
事件处理
src/pages/EventHandle.js
import React, { Component } from 'react'
export default class EventHandle extends Component {
constructor(props){
super(props);
this.state = {
name: ""//显示值
};
//非箭头函数绑定this
this.submit = this.submit.bind(this);
}
submit(){
//打印输入框的值
console.log(this.refs["input"].value);
console.log(this.state.name);
//props传值
this.props.tellme('呵呵哈哈哈');
};
//箭头函数不用绑定this
//单向数据流 没有双向绑定
setChange = event => {
//更新值
this.setState({
name: event.target.value
})
};
render() {
const {name} = this.state;
//props接受传值
const {store} = this.props;
console.log(store.user);
return (
<div>
<h1>EventHandle</h1>
<input value={name} onChange={this.setChange} ref="input"/>
<button onClick={this.submit}>login</button>
</div>
)
}
}
app.js引入
import React from 'react';
// import ClassComponent from './pages/ClassComponent';
import FuncComponent from './pages/FuncComponent';
import EventHandle from './pages/EventHandle';
const store = {
user: 'tom'
}
function tellme(msg){
console.log(msg);
}
function App() {
return (
<div className="App">
{/* <ClassComponent /> */}
{/* <FuncComponent /> */}
<EventHandle store={store} tellme={tellme}/>
</div>
);
}
export default App;
React的生命周期
V16.3之前的生命周期
constructor() 初始化
componentWillMount() 将要挂载
render() 挂载(执行多次)
componentDidMount() 挂载完成
组件运行时
state改变
shouldComponentUpdate() 性能优化点 返回true走更新组件 返回false走(不刷新页面 值会更新)
componentWillUpdate() 组件将要更新
render()
componentDidUpdate() 组件更新完毕
componentWillUnmount() 组件卸载
父组件重新render()改变props
componentWillReceiveProps()
shouldComponentUpdate()...
创建src/pages/LifeCycle.js
import React, { Component } from 'react'
//第一次创建顺序:constructor componentWillMount render componentDidMount v16.3
//第一次创建顺序:constructor getDerivedStateFromProps render componentDidMount v16.4以后
//更新值的时候顺序:shouldComponentUpdate componentWillUpdate render componentWillReceiveProps(componentWillUnmount) componentDidUpdate v16.3
//更新值的时候顺序:shouldComponentUpdate getSnapshotBeforeUpdate render componentDidUpdate v16.4以后
//加UNSAFE_ v17版本可能会废弃
export default class LifeCycle extends Component {
constructor(props){
super(props);
this.state = {
counter: 0//显示值
};
console.log('constructor');
}
//跟之前的componentWillMount类似
static getDerivedStateFromProps(props,state){
console.log('getDerivedStateFromProps');
//返回null 不对state作改变 逢5重置0
return state.counter !== 5? null: {counter: 0};
}
//更新之前 componentWillUpdate类似 值更改触发
getSnapshotBeforeUpdate(prevProps,prevState){
// prevState.counter 拿到上一次的值
console.log('getSnapshotBeforeUpdate');
return null;
}
// UNSAFE_componentWillMount(){
// console.log('componentWillMount');
// }
componentDidMount(){
console.log('componentDidMount');
}
// UNSAFE_componentWillUpdate(){
// console.log('componentWillUpdate');
// }
componentDidUpdate(){
console.log('componentDidUpdate');
}
shouldComponentUpdate(nextProps,nextState){
//nextState.counter就是本次更新的值
console.log('shouldComponentUpdate');
//不等于3就刷新界面
return nextState.counter !== 3;
}
setCounter = () =>{
// console.log('点击时间');
this.setState({
counter: this.state.counter + 1,
});
};
render() {
console.log('render');
const {counter} = this.state;
return (
<div>
<h1></h1>
<p onClick={this.setCounter}>{counter}</p>
{counter !=2 && <Foo counter={counter}/>}
</div>
)
}
}
class Foo extends Component{
// UNSAFE_componentWillReceiveProps(props,state){
// console.log('componentWillReceiveProps');
// }
componentWillUnmount(){
console.log('componentWillUnmount');
}
render(){
const {counter} = this.props;
// console.log(counter);
return (
<div>
<h1>Foo</h1>
<p>{counter}</p>
</div>
)
}
}
App.js引入
import React from 'react';
// import ClassComponent from './pages/ClassComponent';
// import FuncComponent from './pages/FuncComponent';
// import EventHandle from './pages/EventHandle';
import LifeCycle from './pages/LifeCycle';
// const store = {
// user: 'tom'
// }
// function tellme(msg){
// console.log(msg);
// }
function App() {
return (
<div className="App">
{/* <ClassComponent /> */}
{/* <FuncComponent /> */}
{/* <EventHandle store={store} tellme={tellme}/> */}
<LifeCycle/>
</div>
);
}
export default App;