Redux+API制作meme generator

环境配置

新建项目create-react-app redux-meme-generator

安装插件npm i -S redux react-redux redux-thunk react-bootstrap

文件结构

运行项目npm run start,清空src下的文件,建立index.js,引入reactreact-dom。并在src下新建componentactionsreducer文件夹。

src/index.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import React from 'react';
import ReactDOM from 'react-dom';
import App from './component/App';

import {createStore, applyMiddleware} from 'redux';
import rootReducer from './reducer';
import {Provider} from 'react-redux';
import thunk from 'redux-thunk';

import {fetchMemes} from "./actions";

const store = createStore(rootReducer, applyMiddleware(thunk));
store.subscribe(() => console.log('store', store.getState()));
store.dispatch(fetchMemes());

ReactDOM.render(
<Provider store={store}>
<App/>
</Provider>
, document.getElementById('root'));

component/App.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import React, {Component} from 'react';
import {connect} from 'react-redux';

class App extends Component {
render() {
return (
<div>
<h1>Welcome to the Meme Generator!</h1>
</div>
)
}
}

function mapStateToProps(state) {
return state;
}

export default connect(mapStateToProps, null)(App);

通过以上代码就可以有权限从component通过store取得memes,现在可以进行UI操作。

环境设置完毕。

Fetch Memes Asyncchronously

在串接API时需要登录账号密码,我们将这组账号密码封装成一个action

src/actions/secrets.js

1
2
3
4
const username = 'AnnieTsai';
const password = '';

export { username, password };

但我们不想在项目公开时,被其他人看到我们的账号密码。因此可以到.gitignore里将这个action的路径写上src/actions/secrets.js,就不会发布出去。

actions/index.js,编写从json获取memes的逻辑。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
export const RECRIVE_MEMES = 'RESEIVE_MEMES';

function receiveMemes(json) {
const {memes} = json.data;
return {
type: RECRIVE_MEMES,
memes
}
}

function fetchMemesJson() {
return fetch('https://api.imgflip.com/get_memes')
.then(response => response.json())
}

export function fetchMemes() {
return function (dispatch) {
return fetchMemesJson()
.then(json => dispatch(receiveMemes(json)))
}
}

我们可以通过fetch来获得所需要的内容。

Fetch API提供了一个JavaScript接口,用于访问和操作HTTP管道的部分,例如请求和响应。它还提供了一个全局fetch()方法,该方法提供了一种简单、合乎逻辑的方式来跨网络异步获取资源。

套用thunk middileware

reducer/index.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import {combineReducers} from 'redux';
import {RECRIVE_MEMES} from "../actions";

function memes(state = [], action) {
switch (action.type) {
case RECRIVE_MEMES:
return action.memes;
default:
return state;
}
}

const rootReducer = combineReducers({memes});

export default rootReducer;

Listing memes

我们可以借由meme name来区分每一个component,每一个meme对象都有name属性值,让它们能够被识别。另外,我们也需要加上key来判别每个对象的唯一性。

1
2
3
4
5
6
7
8
9
10
<div>
<h2>Welcome to the Meme Generator!</h2>
{
this.props.memes.map((meme, index) => {
return (
<h4 key={index}>{meme.name}</h4>
)
})
}
</div>

Load more

当一个页面有大量的资料时,我们就会进行分页或是浓缩的动作。

通过constructor建立一个设定显示数量的state

src/component/App.js

1
2
3
4
5
6
7
constructor(){
super();

this.state = {
memeLimit: 10
}
}

JavaScript的slice()让我们可以从某个字符串string.slice()或数组Array.slice()提取某一段信息。在渲染的地方加上:slice(0,this,state,memeLimit)

1
2
3
4
5
6
this.props.memes.slice(3, this.state.memeLimit).map((meme,index) => {
//设置为3,该从第4个开始提取,只会显示后面7个
return (
<h4 key={index}>{meme.name}</h4>
)
})

接下来我要制作一个按钮,让使用者可以点击load more,就可以显示更多memes。当使用者点击这个按钮时,便更新state,把memeLimit再加上10。

1
2
3
<div onClick={() => {
this.setState({memeLimit: this.state.memeLimit+10})
}}>Load 10 more memes...</div>

create meme items

现在把图片呈现出来

component/MemeItem.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import React, {Component} from 'react';

class MemeItem extends Component {
render() {
return (
<div>
<img
src={this.props.meme.url}
alt={this.props.meme.name}
/>
<p>
{this.props.meme.name}
</p>
</div>
)
}
}

export default MemeItem;

App.js引入MemeItem.js,并在原本渲染呈现meme name的地方

转换成MemeItemcomponent tag

1
<MemeItem key={index} meme={meme} />

Animating Memes Items

要实现鼠标移动图片之上有动画,可以通过csshover,我们可以通过setState不断地更新hover的状态。在MemeItemcomponent中设置constructor

1
2
3
4
5
6
7
constructor(){
super();

this.state = {
hovered: false
}
}