内容简介:继续【如果你还不知道什么情况的话,建议回到前面的文章看下,做下热身了解。前面的文章我们没有做关于样式太多的操作,这里我们简单的加一些样式,使得我们的应用能够更加具有导航性
继续【 抛弃Redux,迎接React的hooks和context(一) 】文章继续介绍一些新的东西
如果你还不知道什么情况的话,建议回到前面的文章看下,做下热身了解。
样式
前面的文章我们没有做关于样式太多的操作,这里我们简单的加一些样式,使得我们的应用能够更加具有导航性
- 添加下面的样式到文件index.css
.episode-layout {
display: flex;
flex-wrap: wrap;
min-width: 100vh;
}
.episode-box {
padding: 0.5rem;
}
.header {
align-items: center;
background: white;
border-bottom: 1px solid black;
display: flex;
justify-content: space-between;
padding: .5rem;
position: sticky;
top: 0;
}
.header * {
margin: 0;
}
- 在index.js文件中StoreProvider下面加入下面的代码
import './index.css';
-
在App.jsx文件中,给
<section>标签添加className属性,让className等于 film-layout -
在
<section>标签中的state.films.map里面的<section>添加className,让className等于 film-box -
将最后的那个
</div>,在</React.Fragment>标签上面的,移到<p>标签下面。 -
最后给
<div>标签添加属性className,让className等于 header
最后App.jsx的代码如下
import React from 'react';
import { Store } from './Store';
function App() {
const { state, dispatch } = React.useContext(Store);
const fetchDataAction = async () => {
const data = await fetch('https://api.tvmaze.com/singlesearch/shows?q=rick-&-morty&embed=episodes');
const dataJson = await data.json();
return dispatch({
type: 'FETCH_DATA',
payload: dataJson._embedded.episodes
});
}
React.useEffect(() => {
state.films.length === 0 && fetchDataAction();
});
return (
<React.Fragment>
{console.log(state)}
<div className="header">
<h1>Example</h1>
<p>Favourite</p>
</div>
<section className="film-layout">
{
state.films.map(f => {
return (
<section key={f.id} className="film-box">
<img
src={f.image ? f.image.medium : ''}
alt={`Year and Date ${f.name}`}
/>
<div>
{f.name}
</div>
<section>
<div>
Season: {f.season} Number: {f.number}
</div>
</section>
</section>
)
})
}
</section>
</React.Fragment>
);
}
export default App;
让我们再次运行 npm start ,如果已经启动则不需要这个操作,会自动刷新
添加功能
- 仍然是在App.jsx文件中,在包含Season和Number的
</div>标签下面添加下面的代码
<button type='button' onClick={() => toggleCreatorAction(f)}>ADD</button>
- 在 fetchDataAction 函数下面添加 toggleCreatorAction 函数,其代码如下
const toggleCreatorAction = film => {
dispatch({
type: 'CREATOR_ADD',
payload: film
})
}
正如这里面写的, toggleCreatorAction 函数返回一个dispatch,这个dispatch发送一个creator对象到store,你也许已经猜到了这个函数的功能。
- 打开 Store.js ,在 reducer 人中添加下面这个case在 default 上面
case 'CREATOR_ADD':
return {
...state,
creators: [...state.creators, action.payload]
}
当点击按钮ADD的时候, CREATOR_ADD 的case会更新creators数组,并将新的creator对象添加到creators中
- 打开浏览器查看开发者工具,然后点击ADD按钮将会看到creators更新变化的情况
删除功能
- 修改 toggleCreatorAction 函数修改后代码如下
const toggleCreatorAction = film => {
const filmInCreator = state.creators.includes(film)
let dispatchObj = {
type: 'CREATOR_ADD',
payload: film,
}
if (filmInCreator) {
const filmWithoutCreator = state.creators.filter(creator => creator.id !== film.id)
dispatchObj = {
type: 'CREATOR_DEL',
payload: filmWithoutCreator,
}
}
return dispatch(dispatchObj)
}
filmInCreator用来检查creators中是否已经存在film,如果存在的话则进行删除操作,filmWithoutCreator用来移除存在的film,然后用新的filmWithoutCreator来更新creators数组。
- 在Store.js中的reducer中添加一个新的case,代码如下
case 'CREATOR_DEL':
return {
...state,
creators: action.payload
}
上面的功能完成后,该有的功能都差不多了,但是为了向用户展示,正在发生的事情,我们需要再做一些事情
- 修改App.jsx,修改header部分,修改后的代码如下
<header>
<div className="header">
<h1>Example</h1>
<p>Favourite</p>
</div>
<div>
Creator(s) {state.creators.length}
</div>
</header>
- 修改组件,用下面的代码替换掉 ADD
{state.creators.find(creator => creator.id === f.id) ? 'DEL' : 'ADD'}
这段代码使用了 array.find 方法,为了检查film对象的id是否存在于creators数组中,如果存在,则显示 DEL
- 小样式的修改,在
<div>{f.name}</div>下面的<section>,给<section>标签添加一个style,代码如下
style={{ display: 'flex', justifyContent: 'space-between' }}
希望一切顺利,你有代码在浏览器中类似如下。
分隔代码
前面做了一些基本逻辑上的实现操作,下面做一些关于代码拆分的操作
- 创建一个新的文件,叫做FlimList.jsx,其代码如下
import React from 'react';
export default function FilmList(props) {
const { films, toggleCreatorAction, creators } = props;
}
你可能已经明白我们要做的事情了
-
在App.jsx文件中,复制
state.films.map的代码,然后粘贴到 creators 文件中。 -
在 FilmList.jsx 中将
state.films.map替换为return films.map -
将
state.creators.find替换为creators.find
所有步骤做完后, FilmList.jsx 文件中的代码看起来如下
import React from 'react';
export default function FilmList(props) {
const { films, toggleCreatorAction, creators } = props;
return films.map(f => {
return (
<section key={f.id} className="film-box">
<img
src={f.image ? f.image.medium : ''}
alt={`Year and Date ${f.name}`}
/>
<div>
{f.name}
</div>
<section style={{ display: 'flex', justifyContent: 'space-between' }}>
<div>
Season: {f.season} Number: {f.number}
</div>
<button type='button' onClick={() => toggleCreatorAction(f)}>
{creators.find(creator => creator.id === f.id) ? 'DEL' : 'ADD'}
</button>
</section>
</section>
)
})
}
suspense 和 lazy
- 在App.jsx文件中加入下面的代码
const FilmList = React.lazy(() => import('./FilmList'));
-
在
<React.Suspense>嵌套标签<React.Fragment> -
<React.Suspense>标签应该有下面这个属性
**fallback**={<div>Loading...</div>}
-
移除
<section className="film-layout">...</section>部分的代码,并用<FilmList {...props} />替换 -
添加下面的代码在返回组件的上面
const props = {
films: state.films,
toggleCreatorAction,
creators: state.creators,
};
以上所有操作做完之后,保存代码并刷新浏览器应该会正常工作,并且在打开的时候会有一个'Loading...'状态
以上所述就是小编给大家介绍的《抛弃Redux,迎接React的hooks和context(二)》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 抛弃Redux,迎接React的hooks和context(一)
- TLS握手:回顾1.2、迎接1.3
- 告别 2019,迎接 2020:读书、旅行、感情、工作、慈善……
- 智慧停车风景无限好,市场期许中迎接爆发
- ThinkPHP V5.0.14 版本发布——迎接新年
- ThinkPHP V5.0.14 版本发布——迎接新年
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。