生命周期
组件的生命周期指的是组件从创建到结束,包含其中组件的状态变化的这一过程所创建挂载、更新数据、销毁结束的操作
创建挂载函数:constructor、componentWillMount、componentDidMount
数据更新函数:componentWillReceiveProps、shouldComponentUpdate、componentWillUpdate、componentDidUpdate
结束销毁函数:componentWillUnmount
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.bootcdn.net/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/babel-standalone/7.0.0-beta.3/babel.min.js"></script>
</head>
<body>
<div id="main"></div>
<script type="text/babel">
class Header extends React.Component {
componentWillReceiveProps() {
console.log('componentWillReceiveProps'); // 2.1 只有上面返回 true 时,props 发生改变执行
}
componentWillUnmount() {
console.log('componentWillUnmount'); // 组件销毁前执行
}
render() {
return <span>{this.props.count}</span>
}
}
class App extends React.Component {
constructor() {
super();
this.state = { count: 0 };
}
componentWillMount() {
console.log('componentWillMount'); // 1.0 页面启动执行
}
componentDidMount() {
console.log('componentDidMount'); // 1.1 页面启动执行
}
shouldComponentUpdate() {
return true; // true 表示允许返回,false 表示不允许返回
}
componentWillUpdate() {
console.log('componentWillUpdate'); // 2.0 只有上面返回 true 时,state 发生改变执行
}
componentDidUpdate() {
console.log('componentDidUpdate'); // 2.2 只有上面返回 true 时,state 发生改变执行
}
handle = () => {
this.setState({ count: this.state.count + 1 });
}
render() {
const { count } = this.state;
return (
<div>
<h1>生命周期函数: <Header count={count} /></h1>
<button onClick={this.handle}>点击</button>
</div>
);
}
}
ReactDOM.render(
<App />,
document.getElementById('main')
);
</script>
</body>
</html>
todolist 实战
完成一个简单的 todolist 业务功能呈现,包含列表的增、删、改、查(提示:本地存储)
项目分析:将板块分成三大组件,头部处理新增、全选、批量删除业务,中部处理列表渲染、单选、修改、删除业务,底部处理分类统计,由于未涉及到数据库,使用本地存储方式进行数据的编辑操作后的保存。
(1)板块容器
板块容器是一个类组件,用于引用傀儡组件和处理业务逻辑,由于当前未使用 redux 状态管理,板块容器不能称之为一个容器组件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.bootcdn.net/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/babel-standalone/7.0.0-beta.3/babel.min.js"></script>
</head>
<body>
<div id="main"></div>
<script type="text/babel">
class App extends React.Component {
constructor() {
super();
}
render() {
return (
<div>
</div>
);
}
}
ReactDOM.render(
<App />,
document.getElementById('main')
);
</script>
</body>
</html>
(2)傀儡组件
上面分析得到三大组件:头部 HeaderComponent、中部 MainerComponent、底部 FooterComponent
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.bootcdn.net/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/babel-standalone/7.0.0-beta.3/babel.min.js"></script>
</head>
<body>
<div id="main"></div>
<script type="text/babel">
function HeaderComponent (props) {
return (
<div>
</div>
)
}
function MainerComponent (props) {
return (
<div>
</div>
)
}
function FooterComponent (props) {
return (
<div>
</div>
)
}
class App extends React.Component {
constructor() {
super();
}
render() {
return (
<div>
<HeaderComponent />
<MainerComponent />
<FooterComponent />
</div>
);
}
}
ReactDOM.render(
<App />,
document.getElementById('main')
);
</script>
</body>
</html>
分析列表数据:每列存在内容和状态,那么可以得出列表数据是一个元素为对象 { value: ‘’, state: 0 } 的数组集合,可以模拟列表数据,进行数据的传递,通过遍历将列表数据渲染出来。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.bootcdn.net/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/babel-standalone/7.0.0-beta.3/babel.min.js"></script>
</head>
<body style="display: flex; height: 500px; align-items: center; justify-content: center;">
<div id="main"></div>
<script type="text/babel">
function HeaderComponent (props) {
return (
<div>
</div>
)
}
function MainerComponent (props) {
return (
<div>
{
props.list.map((item, index) => {
return (
<div key={index}>
<input type="checkbox" checked={item.state} />
<input value={item.value} />
<button>修改</button>
<button>删除</button>
</div>
)
})
}
</div>
)
}
function FooterComponent (props) {
return (
<div>
</div>
)
}
class App extends React.Component {
constructor() {
super();
let list = [
{ state: 0, value: '苹果' },
{ state: 0, value: '橘子' },
{ state: 0, value: '香蕉' },
{ state: 0, value: '李子' },
{ state: 0, value: '樱桃' },
{ state: 0, value: '菠萝' },
];
this.state = { list } // 1. 初始化状态
}
render() {
return (
<div>
<HeaderComponent />
<MainerComponent list={this.state.list} />
<FooterComponent />
</div>
);
}
}
ReactDOM.render(
<App />,
document.getElementById('main')
);
</script>
</body>
</html>
按 F12 会出现一个警告提醒,大致的意思是需要绑定一个 onChange 事件,这是因为表单控件是属于受控组件,如果要多表单控件数据进行修改操作时,需要手动进行非受控操作,即:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.bootcdn.net/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/babel-standalone/7.0.0-beta.3/babel.min.js"></script>
</head>
<body style="display: flex; height: 500px; align-items: center; justify-content: center;">
<div id="main"></div>
<script type="text/babel">
function HeaderComponent (props) {
return (
<div>
</div>
)
}
function MainerComponent (props) {
// 伪造的文本框输入编辑,调用父组件文本框编辑:表单控件为受控组件,需要监听 onChange 事件
const fakeEditeItem = (event, item) => props.editeItem(event, item);
return (
<div>
{
props.list.map((item, index) => {
return (
<div key={index}>
<input type="checkbox" checked={item.state} />
<input value={item.value} onChange={(event) => fakeEditeItem(event, index)} />
<button>修改</button>
<button>删除</button>
</div>
)
})
}
</div>
)
}
function FooterComponent (props) {
return (
<div>
</div>
)
}
class App extends React.Component {
constructor() {
super();
let list = [
{ state: 0, value: '苹果' },
{ state: 0, value: '橘子' },
{ state: 0, value: '香蕉' },
{ state: 0, value: '李子' },
{ state: 0, value: '樱桃' },
{ state: 0, value: '菠萝' },
];
this.state = { list } // 1. 初始化状态
}
editeItem = (event, index) => {
let { list } = this.state;
list[index].value = event.target.value;
this.setState({ list });
}
render() {
return (
<div>
<HeaderComponent />
<MainerComponent list={this.state.list} editeItem={this.editeItem} />
<FooterComponent />
</div>
);
}
}
ReactDOM.render(
<App />,
document.getElementById('main')
);
</script>
</body>
</html>
由于当前列表数据是采用声明式的,所以即使修改了数据,但刷新浏览器依然是声明式的数据,这里通过使用本地缓存的方式进行数据的读写操作
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.bootcdn.net/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/babel-standalone/7.0.0-beta.3/babel.min.js"></script>
</head>
<body style="display: flex; height: 500px; align-items: center; justify-content: center;">
<div id="main"></div>
<script type="text/babel">
function HeaderComponent (props) {
return (
<div>
</div>
)
}
function MainerComponent (props) {
// 伪造的文本框输入编辑,调用父组件文本框编辑:表单控件为受控组件,需要监听 onChange 事件
const fakeEditeItem = (event, item) => props.editeItem(event, item);
// 伪造的文本框输入提交,调用父组件文本框提交
const fakeUpdataItem = () => props.updataItem();
return (
<div>
{
props.list.map((item, index) => {
return (
<div key={index}>
<input type="checkbox" checked={item.state} />
<input value={item.value} onChange={(event) => fakeEditeItem(event, index)} />
<button onClick={fakeUpdataItem}>修改</button>
<button>删除</button>
</div>
)
})
}
</div>
)
}
function FooterComponent (props) {
return (
<div>
</div>
)
}
class App extends React.Component {
constructor() {
super();
let list = JSON.parse(localStorage.getItem('list')) || [
{ state: 0, value: '苹果' },
{ state: 0, value: '橘子' },
{ state: 0, value: '香蕉' },
{ state: 0, value: '李子' },
{ state: 0, value: '樱桃' },
{ state: 0, value: '菠萝' },
];
this.state = { list } // 1. 初始化状态
}
editeItem = (event, index) => {
let { list } = this.state;
list[index].value = event.target.value;
this.setState({ list });
}
updataItem = () => {
let { list } = this.state;
localStorage.setItem('list', JSON.stringify(list));
}
render() {
return (
<div>
<HeaderComponent />
<MainerComponent list={this.state.list} editeItem={this.editeItem} updataItem={this.updataItem} />
<FooterComponent />
</div>
);
}
}
ReactDOM.render(
<App />,
document.getElementById('main')
);
</script>
</body>
</html>
通过列表索引值传值,进行列表内列的删除操作,并将最后的列表缓存本地保存以达到数据更新操作
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.bootcdn.net/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/babel-standalone/7.0.0-beta.3/babel.min.js"></script>
</head>
<body style="display: flex; height: 500px; align-items: center; justify-content: center;">
<div id="main"></div>
<script type="text/babel">
function HeaderComponent (props) {
return (
<div>
</div>
)
}
function MainerComponent (props) {
// 伪造的文本框输入编辑,调用父组件文本框编辑:表单控件为受控组件,需要监听 onChange 事件
const fakeEditeItem = (event, item) => props.editeItem(event, item);
// 伪造的文本框输入提交,调用父组件文本框提交
const fakeUpdataItem = () => props.updataItem();
// 伪造的复选框单选删除,调用父组件复选框单选删除
const fakeDeleteItem = (index) => props.deleteItem(index);
return (
<div>
{
props.list.map((item, index) => {
return (
<div key={index}>
<input type="checkbox" checked={item.state} />
<input value={item.value} onChange={(event) => fakeEditeItem(event, index)} />
<button onClick={fakeUpdataItem}>修改</button>
<button onClick={() => fakeDeleteItem(index)}>删除</button>
</div>
)
})
}
</div>
)
}
function FooterComponent (props) {
return (
<div>
</div>
)
}
class App extends React.Component {
constructor() {
super();
let list = JSON.parse(localStorage.getItem('list')) || [
{ state: 0, value: '苹果' },
{ state: 0, value: '橘子' },
{ state: 0, value: '香蕉' },
{ state: 0, value: '李子' },
{ state: 0, value: '樱桃' },
{ state: 0, value: '菠萝' },
];
this.state = { list } // 1. 初始化状态
}
editeItem = (event, index) => {
let { list } = this.state;
list[index].value = event.target.value;
this.setState({ list });
}
updataItem = () => {
let { list } = this.state;
localStorage.setItem('list', JSON.stringify(list));
}
deleteItem = index => {
let { list } = this.state;
list = list.filter((item, idx) => idx !== index);
this.setState({ list });
localStorage.setItem('list', JSON.stringify(list));
}
render() {
return (
<div>
<HeaderComponent />
<MainerComponent list={this.state.list} editeItem={this.editeItem} updataItem={this.updataItem} deleteItem={this.deleteItem} />
<FooterComponent />
</div>
);
}
}
ReactDOM.render(
<App />,
document.getElementById('main')
);
</script>
</body>
</html>
列表选中需要改变自身的状态,这里通过状态取反后再取正,得到状态数值类型
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.bootcdn.net/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/babel-standalone/7.0.0-beta.3/babel.min.js"></script>
</head>
<body style="display: flex; height: 500px; align-items: center; justify-content: center;">
<div id="main"></div>
<script type="text/babel">
function HeaderComponent (props) {
return (
<div>
</div>
)
}
function MainerComponent (props) {
// 伪造的单选框选中更新,调用父组件单选框选中更新
const fakeRadioItem = (index) => props.radioItem(index);
// 伪造的文本框输入编辑,调用父组件文本框编辑:表单控件为受控组件,需要监听 onChange 事件
const fakeEditeItem = (event, item) => props.editeItem(event, item);
// 伪造的文本框输入提交,调用父组件文本框提交
const fakeUpdataItem = () => props.updataItem();
// 伪造的复选框单选删除,调用父组件复选框单选删除
const fakeDeleteItem = (index) => props.deleteItem(index);
return (
<div>
{
props.list.map((item, index) => {
return (
<div key={index}>
<input type="checkbox" checked={item.state} onChange={() => fakeRadioItem(index)} />
<input value={item.value} onChange={(event) => fakeEditeItem(event, index)} />
<button onClick={fakeUpdataItem}>修改</button>
<button onClick={() => fakeDeleteItem(index)}>删除</button>
</div>
)
})
}
</div>
)
}
function FooterComponent (props) {
return (
<div>
</div>
)
}
class App extends React.Component {
constructor() {
super();
let list = JSON.parse(localStorage.getItem('list')) || [
{ state: 0, value: '苹果' },
{ state: 0, value: '橘子' },
{ state: 0, value: '香蕉' },
{ state: 0, value: '李子' },
{ state: 0, value: '樱桃' },
{ state: 0, value: '菠萝' },
];
this.state = { list } // 1. 初始化状态
}
radioItem = index => {
let { list } = this.state;
list[index].state = +!list[index].state;
this.setState({ list });
localStorage.setItem('list', JSON.stringify(list));
}
editeItem = (event, index) => {
let { list } = this.state;
list[index].value = event.target.value;
this.setState({ list });
}
updataItem = () => {
let { list } = this.state;
localStorage.setItem('list', JSON.stringify(list));
}
deleteItem = index => {
let { list } = this.state;
list = list.filter((item, idx) => idx !== index);
this.setState({ list });
localStorage.setItem('list', JSON.stringify(list));
}
render() {
return (
<div>
<HeaderComponent />
<MainerComponent radioItem={this.radioItem} list={this.state.list} editeItem={this.editeItem} updataItem={this.updataItem} deleteItem={this.deleteItem} />
<FooterComponent />
</div>
);
}
}
ReactDOM.render(
<App />,
document.getElementById('main')
);
</script>
</body>
</html>
底部组件通过统计选中,未选中数即总数减掉选中数量
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.bootcdn.net/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/babel-standalone/7.0.0-beta.3/babel.min.js"></script>
</head>
<body style="display: flex; height: 500px; align-items: center; justify-content: center;">
<div id="main"></div>
<script type="text/babel">
function HeaderComponent (props) {
return (
<div>
</div>
)
}
function MainerComponent (props) {
// 伪造的单选框选中更新,调用父组件单选框选中更新
const fakeRadioItem = (index) => props.radioItem(index);
// 伪造的文本框输入编辑,调用父组件文本框编辑:表单控件为受控组件,需要监听 onChange 事件
const fakeEditeItem = (event, item) => props.editeItem(event, item);
// 伪造的文本框输入提交,调用父组件文本框提交
const fakeUpdataItem = () => props.updataItem();
// 伪造的复选框单选删除,调用父组件复选框单选删除
const fakeDeleteItem = (index) => props.deleteItem(index);
return (
<div>
{
props.list.map((item, index) => {
return (
<div key={index}>
<input type="checkbox" checked={item.state} onChange={() => fakeRadioItem(index)} />
<input value={item.value} onChange={(event) => fakeEditeItem(event, index)} />
<button onClick={fakeUpdataItem}>修改</button>
<button onClick={() => fakeDeleteItem(index)}>删除</button>
</div>
)
})
}
</div>
)
}
function FooterComponent (props) {
let { list } = props;
let selected = list.filter(item => item.state === 1).length, unselect = list.length - selected;
return <div>已选:{selected}未选:{unselect}</div>
}
class App extends React.Component {
constructor() {
super();
let list = JSON.parse(localStorage.getItem('list')) || [
{ state: 0, value: '苹果' },
{ state: 0, value: '橘子' },
{ state: 0, value: '香蕉' },
{ state: 0, value: '李子' },
{ state: 0, value: '樱桃' },
{ state: 0, value: '菠萝' },
];
this.state = { list } // 1. 初始化状态
}
radioItem = index => {
let { list } = this.state;
list[index].state = +!list[index].state;
this.setState({ list });
localStorage.setItem('list', JSON.stringify(list));
}
editeItem = (event, index) => {
let { list } = this.state;
list[index].value = event.target.value;
this.setState({ list });
}
updataItem = () => {
let { list } = this.state;
localStorage.setItem('list', JSON.stringify(list));
}
deleteItem = index => {
let { list } = this.state;
list = list.filter((item, idx) => idx !== index);
this.setState({ list });
localStorage.setItem('list', JSON.stringify(list));
}
render() {
return (
<div>
<HeaderComponent />
<MainerComponent radioItem={this.radioItem} list={this.state.list} editeItem={this.editeItem} updataItem={this.updataItem} deleteItem={this.deleteItem} />
<FooterComponent list={this.state.list} />
</div>
);
}
}
ReactDOM.render(
<App />,
document.getElementById('main')
);
</script>
</body>
</html>
同理,头部新增输入框也需要手动改为非受控组件进行数据编辑,由于所有业务都是在板块容器内操作的,这里需要传递两个变量到头部组件中:inputvalue 新增输入内容和 allcheck 全选状态,当然后面使用 Hooks 钩子函数的话就不需要啦。
这里需要注意的是:
- allcheck 全选状态不一定为非选中状态,所以在初始化时,判断是否全选;
- 删除唯一一个未选中列,allcheck 全选状态变更选中状态;
- 全部删除列表所有列或部分列,判断 allcheck 全选状态是否全选;
- 最后一个单选列选中的情况下,全选状态也要选中状态;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.bootcdn.net/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/babel-standalone/7.0.0-beta.3/babel.min.js"></script>
</head>
<body style="display: flex; height: 500px; align-items: center; justify-content: center;">
<div id="main"></div>
<script type="text/babel">
function HeaderComponent (props) {
// 伪造的文本框输入更新,调用父组件文本框更新:表单控件为受控组件,需要监听 onChange 事件
const fakeInputItem = event => props.inputItem(event);
// 伪造的文本框输入新增,调用父组件文本框新增
const fakeNewlyItem = () => props.newlyItem();
// 伪造的复选框选中更新,调用父组件复选框选中更新
const fakeCheckItem = () => props.checkItem();
// 伪造的复选框全选删除,调用父组件复选框全选删除
const fakeClearItem = () => props.clearItem();
return (
<div>
<input type="checkbox" checked={props.allcheck} onChange={fakeCheckItem} />
<input value={props.inputvalue} onChange={fakeInputItem} />
<button onClick={fakeNewlyItem}>新增</button>
<button onClick={fakeClearItem}>批量删除</button>
</div>
)
}
function MainerComponent (props) {
// 伪造的单选框选中更新,调用父组件单选框选中更新
const fakeRadioItem = (index) => props.radioItem(index);
// 伪造的文本框输入编辑,调用父组件文本框编辑:表单控件为受控组件,需要监听 onChange 事件
const fakeEditeItem = (event, item) => props.editeItem(event, item);
// 伪造的文本框输入提交,调用父组件文本框提交
const fakeUpdataItem = () => props.updataItem();
// 伪造的复选框单选删除,调用父组件复选框单选删除
const fakeDeleteItem = (index) => props.deleteItem(index);
return (
<div>
{
props.list.map((item, index) => {
return (
<div key={index}>
<input type="checkbox" checked={item.state} onChange={() => fakeRadioItem(index)} />
<input value={item.value} onChange={(event) => fakeEditeItem(event, index)} />
<button onClick={fakeUpdataItem}>修改</button>
<button onClick={() => fakeDeleteItem(index)}>删除</button>
</div>
)
})
}
</div>
)
}
function FooterComponent (props) {
let { list } = props;
let selected = list.filter(item => item.state === 1).length, unselect = list.length - selected;
return <div>已选:{selected}未选:{unselect}</div>
}
class App extends React.Component {
constructor() {
super();
let list = JSON.parse(localStorage.getItem('list')) || [];
list.length === 0 && localStorage.setItem('list', JSON.stringify(list));
// 如果没有数据全选状态为 false,否则根据列表状态是否存在未选的情况下为 false,只有不存在未选的情况下为 true
let index = list.length === 0 ? 0 : list.findIndex(item => item.state === 0);
this.state = { list, allcheck: index === -1 ? 1 : 0, inputvalue: '' } // 1. 初始化状态
}
inputItem = (event) => {
this.setState({ inputvalue: event.target.value });
}
newlyItem = () => {
let { inputvalue, list } = this.state;
list.push({ name: inputvalue, state: 0 });
this.setState({ list, inputvalue: '' });
localStorage.setItem('list', JSON.stringify(list));
}
checkItem = () => {
let { allcheck, list } = this.state;
allcheck = allcheck === 1 ? 0 : 1;
list = list.map(item => {
if (item.state !== allcheck) {
item.state = allcheck;
}
return item;
})
this.setState({ allcheck, list });
localStorage.setItem('list', JSON.stringify(list));
}
clearItem = () => {
let { list } = this.state;
list = list.filter(item => item.state !== 1);
// 如果没有数据全选状态为 false,否则根据列表状态是否存在未选的情况下为 false,只有不存在未选的情况下为 true
let len = list.length === 0 ? 0 : list.findIndex(item => item.state === 0);
this.setState({ list, allcheck: len === -1 ? 1 : 0 });
localStorage.setItem('list', JSON.stringify(list));
}
radioItem = index => {
let { list } = this.state;
list[index].state = +!list[index].state;
let { state } = list[index];
let idx = list.findIndex(item => item.state !== state);
let allcheck = idx === -1 ? state : 0;
this.setState({ list, allcheck });
localStorage.setItem('list', JSON.stringify(list));
}
editeItem = (event, index) => {
let { list } = this.state;
list[index].value = event.target.value;
this.setState({ list });
}
updataItem = () => {
let { list } = this.state;
localStorage.setItem('list', JSON.stringify(list));
}
deleteItem = index => {
let { list } = this.state;
list = list.filter((item, idx) => idx !== index);
// 如果没有数据全选状态为 false,否则根据列表状态是否存在未选的情况下为 false,只有不存在未选的情况下为 true
let len = list.length === 0 ? 0 : list.findIndex(item => item.state === 0);
this.setState({ list, allcheck: len === -1 ? 1 : 0 });
localStorage.setItem('list', JSON.stringify(list));
}
render() {
return (
<div>
<HeaderComponent inputvalue={this.state.inputvalue} inputItem={this.inputItem} newlyItem={this.newlyItem} allcheck={this.state.allcheck} checkItem={this.checkItem} clearItem={this.clearItem} />
<MainerComponent radioItem={this.radioItem} list={this.state.list} editeItem={this.editeItem} updataItem={this.updataItem} deleteItem={this.deleteItem} />
<FooterComponent list={this.state.list} />
</div>
);
}
}
ReactDOM.render(
<App />,
document.getElementById('main')
);
</script>
</body>
</html>
技巧点
- 遇到一个 Huge Page,不要急着写代码,需要分析页面元素,组件分化,抽丝剥茧;
- 傀儡组件方法名称与容器组件执行方法名称确保一致,增强代码可读性;
- 逻辑业务一层一层写,计算方式要简洁,数组索引、过滤可配用,业务要全面思维;