(1)创建项目
全局安装:nmp install -g create-react-app
查看版本:create-react-app --version
(2)组件化开发
其实react的项目跟vue的项目都差不多,index.js是入口函数,App.js是根组件;
挂载的原理跟我之前写过的vue项目也一样
把之前写过的Task练习按照组件化开发的模式分解,大概成这样
这其中的头部和尾部就是src目录下component的Header和Footer
只是简单的模拟一下组件化开发
//index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(<App />,document.getElementById('root'));
//App.js
import React from 'react';
import Header from './components/Header';
import Footer from './components/Footer';
import TaskMain from './pages/Task';
class App extends React.Component {
render() {
return (
<div>
{/*Header*/}
<Header></Header>
{/*TaskMain*/}
<TaskMain></TaskMain>
{/*Footer*/}
<Footer></Footer>
</div>
)
}
}
export default App;
//Task->index.js
import React from 'react';
import AddTask from './components/AddTask'
import TaskList from './components/TaskList'
class TaskMain extends React.Component {
state = {
tasks: []
}
//添加 task为AddTask组件传来参数
addTask = (task) => {
const { tasks } = this.state
//使任务不为空
if (!task) {
return
}
//使每个任务都有独立的时间
let taskNew = { task: task, date: new Date().toLocaleTimeString() }
// unshift 是新数组的长度 不是新的数组
tasks.unshift(taskNew)
this.setState({
tasks: tasks,
})
}
//删除
deleteTask = (index) => {
const { tasks } = this.state
tasks.splice(index, 1)
this.setState({
tasks
}, () => { })
}
render() {
return (
<div>
<h1>Today Tasks : {this.state.tasks.length}</h1>
<AddTask addTask={this.addTask} />
<TaskList tasks={this.state.tasks} deleteTask={this.deleteTask} />
</div>
)
}
}
export default TaskMain
//Task->components->AddTask.js
import React from 'react';
//添加任务组件
class AddTask extends React.Component {
state = { task: '' }
//输入框同步
handelChange = (e) => {
this.setState({
task: e.target.value
}, () => { })
}
handleAddTask = () => {
const { task } = this.state
this.props.addTask(task)
this.setState({
task: ''
})
}
render() {
return (
<div>
<input type="text" value={this.state.task} onChange={this.handelChange} />
<button onClick={this.handleAddTask}>添加</button>
</div>
)
}
}
export default AddTask
//Task->components->TaskItem.js
//单项任务组件
function TaskItem(props) {
function handleDelete() {
props.deleteTask(props.index)
}
return (
<li>
<span>{props.index + 1}--{props.task}--{props.date}</span>
<button onClick={handleDelete}>delete</button>
</li>
)
}
export default TaskItem
//Task->components->TaskList.js
import TaskItem from "./TaskItem"
//任务列表组件
function TaskList(props) {
return (
<div>
<ul>
{
// item是一个对象
props.tasks.map((item, index) => {
return <TaskItem key={index} index={index} task={item.task} date={item.date} deleteTask={props.deleteTask} />
})
}
</ul>
</div>
)
}
export default TaskList
(3)redux
由于真实项目十分庞大,所以组件间传递状态和值是一个很难解决的问题
这时用redux,它能利用store统一管理状态
下面是redux的具体工作流程和一个redux案例
store是一个仓库,里面有各种各样的方法
可以利用这些方法在store内管理状态
具体流程就是:
视图层想改变state时,先通过actionCreator产生action
接着用store.dispatch方法把action传给reducer
reducer根据action进行逻辑处理
生成新的state返回给store
最后再由store传给视图层进行渲染
//AppCountRedux.js
import {Component} from 'react'
import store from './store'
import {incrementAction,decrementAction} from './store/actionCreator'
class App extends Component {
//store.getState()可以取到reducer中的返回值,同步数据
state = { count:store.getState()}
constructor(){
super()
this.state = {count:store.getState()}
//监听,store里的reducer一旦产生了新值,就会调用this.asyncState
store.subscribe(this.asyncState)
}
asyncState=()=>{
//获取最新数据,同步到state里
this.setState({count:store.getState()})
}
increment=()=>{
//store.dispatch中的参数就是action,把它传给reducer
//要加括号执行,因为action已经被封装成函数了
store.dispatch(incrementAction())
}
decrement=()=>{
store.dispatch(decrementAction())
}
render() {
return (
<div>
Clicked:{this.state.count} times
<button onClick={this.increment}>+</button>
<button onClick={this.decrement}>-</button>
</div>
);
}
}
export default App;
//AppCountRedux(对象).js
//与上一段代码的主要差别在于reducer中的参数格式不同
import {Component} from 'react'
import store from './store'
import {incrementAction,decrementAction} from './store/actionCreator'
class App extends Component {
//store.getState()可以取到reducer中的返回值,同步数据
constructor(){
super()
this.state = store.getState()
//监听,store里的reducer一旦产生了新值,就会调用this.asyncState
store.subscribe(this.asyncState)
}
asyncState=()=>{
//获取最新数据,同步到state里
this.setState(store.getState())
}
increment=()=>{
//store.dispatch中的参数就是action,把它传给reducer
//要加括号执行,因为action已经被封装成函数了
store.dispatch(incrementAction())
}
decrement=()=>{
store.dispatch(decrementAction())
}
render() {
return (
<div>
Clicked:{this.state.count} times
<button onClick={this.increment}>+</button>
<button onClick={this.decrement}>-</button>
</div>
);
}
}
export default App;
//actionCreator.js
//统一管理,增强action
//因为reducer不适合写副作用代码,所以都写到action里
import * as constant from './constant'
export const incrementAction = (payload) => {
return {type :constant.INCREMENT,payload:payload}
}
export const decrementAction = () => ({type :constant.DECREMENT})
//constant.js
//维护常量
//因为actionCreator和reducer中都用到相同的变量而且必须保持一致
//所以用一个公共的js文件来维护常量
export const INCREMENT = 'increment'
export const DECREMENT = 'decrement'
//store->index.js
import {createStore} from 'redux'
import reducer from './reducer'
//创建仓库
//store本身只是一个仓库,它要调用reducer这个帮手来完成工作
//逻辑代码都在reducer中写
const store = createStore(reducer)
export default store
//reducer.js
import * as constant from './constant'
//默认state值
//数字格式
const defaultState = 0
//对象格式
const defaultState = {count : 0}
//reducer实际就是一个纯函数
//第一个参数是状态;第二个action
//接收view层中dispatch发送的action,利用action中的值来进行判断处理
//action返回值是一个对象
const reducer = (state = defaultState,action) =>{
switch(action.type){
case constant.INCREMENT:
//数字格式
return state+1
//此处的返回对象并不是在默认值的内存空间上更改值
//而是新开辟了一块空间,创造一个新的对象
return {count:state.count+1}
case constant.DECREMENT:
return state-1
return {count:state.count-1}
default:
return state
}
}
export default reducer