前端关于Recat面试题(七)

121.Flux 和 Redux 之间有什么区别?

以下是 Flux 和 Redux 之间的主要区别

Flux Redux
状态是可变的 状态是不可变的
Store 包含状态和更改逻辑 存储和更改逻辑是分开的
存在多个 Store 仅存在一个 Store
所有的 Store 都是断开连接的 带有分层 reducers 的 Store
它有一个单独的 dispatcher 没有 dispatcher 的概念
React 组件监测 Store 容器组件使用连接函数

122.mapStateToProps()mapDispatchToProps() 之间有什么区别?

mapStateToProps()是一个实用方法,它可以帮助您的组件获得最新的状态(由其他一些组件更新):

const mapStateToProps = (state) => {
  return {
    todos: getVisibleTodos(state.todos, state.visibilityFilter)
  }
}

mapDispatchToProps()是一个实用方法,它可以帮助你的组件触发一个动作事件(可能导致应用程序状态改变的调度动作):

const mapDispatchToProps = (dispatch) => {
  return {
    onTodoClick: (id) => {
      dispatch(toggleTodo(id))
    }
  }
}

123.如何在组件外部访问 Redux 存储的对象?

使用connect连接 React 组件与 Redux store。连接操作不会改变原来的组件类。反而返回一个新的已与 Redux store 连接的组件类。

import { connect } from 'react-redux'

//将state状态映射到属性里面,之后可以通过props获取
const mapStatetoProps=(state)=>{
    return {num:state.counter,city:state.city}
}

//addFn 自动有了dispatch的功能 onClick={addFn} ; addFn  minusFn  minusFn会被映射到props里面
const mapDispatchToProps={addFn,minusFn,addAsynFn,changeCityFn}

//为App组件提供数据和逻辑。mapStateToProps负责将state的数据映射到展示组件的this.props。mapDispatchToProps负责定义发送action的函数映射到展示组件的this.props
App=connect(mapStatetoProps,mapDispatchToProps)(App)

export default App

124.Redux 中的 Action 是什么?

Actions是纯 JavaScript 对象或信息的有效负载,可将数据从您的应用程序发送到您的 Store。 它们是 Store 唯一的数据来源。 Action 必须具有指示正在执行的操作类型的 type 属性。

例如,表示添加新待办事项的示例操作:

{
  type: ADD_TODO,
  text: 'Add todo item'
}

125.如何在加载时触发 Action?

您可以在componentDidMount()方法中触发 Action,然后在render()方法中可以验证数据。

class App extends Component {
  componentDidMount() {
    this.props.fetchData()
  }

  render() {
    return this.props.isLoaded
      ? <div>{'Loaded'}</div>
      : <div>{'Not Loaded'}</div>
  }
}

const mapStateToProps = (state) => ({
  isLoaded: state.isLoaded
})

const mapDispatchToProps = { fetchData }

export default connect(mapStateToProps, mapDispatchToProps)(App)

126.在 React 中如何使用 Redux 的 connect() ?

您需要按照两个步骤在容器中使用您的 Store:

  1. 使用mapStateToProps(): 它将 Store 中的状态变量映射到您指定的属性。

  2. 将上述属性连接到容器: mapStateToProps函数返回的对象连接到容器。你可以从react-redux导入connect()

    import React from 'react'
    import { connect } from 'react-redux'
    
    class App extends React.Component {
      render() {
        return <div>{this.props.containerData}</div>
      }
    }
    
    function mapStateToProps(state) {
      return { containerData: state.data }
    }
    
    export default connect(mapStateToProps)(App)
    
    

127.如何在 Redux 中重置状态?

最简单的实现方法就是为每个独立的 store 添加RESET_APP 的 action,每次需要 reset 的时候,dispatch 这个 action 即可,如下代码

const usersDefaultState = []

const users = (state = usersDefaultState, { type, payload }) => {
  switch (type) {
   case "RESET_APP":
     return usersDefaultState;
    case "ADD_USER":
      return [...state, payload];
    default:
      return state;
  }
};

这样虽然简单,但是当独立的 store 较多时,需要添加很多 action,而且需要很多个 dispatch 语句去触发
dispatch({ type: RESET_USER });
dispatch({ type: RESET_ARTICLE });
dispatch({ type: RESET_COMMENT });

不过这里一种更优雅的实现,需要用到一个小技巧,看下面代码:

const usersDefaultState = []
const users = (state = usersDefaultState, { type, payload }) => {...}

当函数参数 state 为 undefined 时,state 就会去 usersDefaultState 这个默认值,利用这个技巧,我们可以在 rootReducers 中检测 RESET_DATA action,直接赋值 undefined 就完成了所有 store 的数据重置。实现代码如下:

我们通常这样导出所有的 reducers

// reducers.js
const rootReducer = combineReducers({
  /* your app’s top-level reducers */
})

export default rootReducer;

先封装一层,combineReducers 返回 reducer 函数,不影响功能

// reducers.js
const appReducer = combineReducers({
  /* your app’s top-level reducers */
})

const rootReducer = (state, action) => {
  return appReducer(state, action)
}

export default rootReducer;

检测到特定重置数据的 action 后利用 undefined 技巧 (完整代码)

// reducers.js
const appReducer = combineReducers({
  /* your app’s top-level reducers */
})

const rootReducer = (state, action) => {
  if (action.type === 'RESET_DATA') {
    state = undefined
  }

  return appReducer(state, action)
}

128.React 上下文和 React Redux 之间有什么区别?

您可以直接在应用程序中使用Context,这对于将数据传递给深度嵌套的组件非常有用。而Redux功能更强大,它还提供了 Context API 无法提供的大量功能。此外,React Redux 在内部使用上下文,但它不会在公共 API 中有所体现。

129.如何在 Redux 中发起 AJAX 请求?

当在redux中有异步操作的时候,可以使用redux-thunk中间件,它允许您定义异步操作。

让我们举个例子,使用fetch API将特定帐户作为 AJAX 调用获取:

export function fetchAccount(id) {
  return dispatch => {
    dispatch(setLoadingAccountState()) // Show a loading spinner
    fetch(`/account/${id}`, (response) => {
      dispatch(doneFetchingAccount()) // Hide loading spinner
      if (response.status === 200) {
        dispatch(setAccount(response.json)) // Use a normal function to set the received state
      } else {
        dispatch(someError)
      }
    })
  }
}

function setAccount(data) {
 return { type: 'SET_Account', data: data }
}

130.我需要将所有状态保存到 Redux 中吗?我应该使用 react 的内部状态吗?

这取决于开发者的决定。一般情况下,组件UI的状态控制的数据我们可以放在组件内部声明。而如果有多个组件要共享的数据、该数据有多个派生数据、该数据需要缓存等情况我们可以放在redux中

131.React Redux 中展示组件和容器组件之间的区别是什么?

展示组件是一个类或功能组件,用于描述应用程序的展示部分(没有使用connect包裹的组件是展示组件)

容器组件是连接到 Redux Store的组件的非正式术语(使用connect包裹之后返回的新组件)。容器组件订阅 Redux 状态更新和dispatch操作,它们通常不呈现 DOM 元素;他们将渲染委托给展示性的子组件。

132.Redux 中常量的用途是什么?

常量允许您在使用 IDE 时轻松查找项目中该特定功能的所有用法。它还可以防止你拼写错误,在这种情况下,你会立即得到一个ReferenceError

通常我们会将它们保存在一个文件中(constants.jsactionTypes.js)。

export const ADD_TODO = 'ADD_TODO'
export const DELETE_TODO = 'DELETE_TODO'
export const EDIT_TODO = 'EDIT_TODO'
export const COMPLETE_TODO = 'COMPLETE_TODO'
export const COMPLETE_ALL = 'COMPLETE_ALL'
export const CLEAR_COMPLETED = 'CLEAR_COMPLETED'

在 Redux 中,您可以在两个地方使用它们:

  1. 在 Action 创建时:

    让我们看看 actions.js:

    import { ADD_TODO } from './actionTypes';
    
    export function addTodo(text) {
      return { type: ADD_TODO, text }
    }
    
    
  2. 在 reducers 里:

    让我们创建 reducer.js 文件:

    import { ADD_TODO } from './actionTypes'
    
    export default (state = [], action) => {
      switch (action.type) {
        case ADD_TODO:
          return [
            ...state,
            {
              text: action.text,
              completed: false
            }
          ];
        default:
          return state
      }
    }
    
    

133.编写 mapDispatchToProps() 有哪些不同的方法?

有一些方法可以将action creators绑定到mapDispatchToProps()中的dispatch()。以下是可能的写法:

const mapDispatchToProps = (dispatch) => ({
 action: () => dispatch(action())
})

const mapDispatchToProps = (dispatch) => ({
 action: bindActionCreators(action, dispatch)
})

const mapDispatchToProps = { action }

第三种写法只是第一种写法的简写。

134.如何构建 Redux 项目目录?

大多数项目都有几个顶级目录,如下所示:

  1. Components: 用于dumb组件,Redux 不必关心的组件。
  2. Containers: 用于连接到 Redux 的smart组件。
  3. Actions: 用于所有 Action 创建器,其中文件名对应于应用程序的一部分。
  4. Reducers: 用于所有 reducer,其中文件名对应于state key。
  5. Store: 用于 Store 初始化。

这种结构适用于中小型项目。

135.什么是 redux-saga?

redux-saga是一个库,旨在解决 React/Redux 项目中异步问题(数据获取等异步操作和访问浏览器缓存等可能产生副作用的动作)更容易,更好。

这个包在 NPM 上有发布:

$ npm install --save redux-saga

136.在 redux-saga 中 call()put() 之间有什么区别?

   put:  用于触发action
        yield put({ type: 'todos/add', payload: 'Learn Dva'});
   
   call:用于调用异步逻辑,支持Promise。
        const result = yield call(fetch, '/todos');
        这个call与JS的call用法大概一致,这个call的第一个参数是你要调用的函数,第二个参数开始是你要传递的参数,可一 一传递。
        
        
        
   effects: {
        // 访问接口获取数据 并且保存数据
        *fetchUserList({ payload: { page = 1 } }, { call, put }) {
            const { data } = yield call(queryUserList, { page });
            yield put({
                type: 'save',
                payload: {
                    list: data.list,
                    total: parseInt(data.total, 10),
                    page: parseInt(data.page, 10)
                }
            });
        },
    },

137.什么是 Redux Thunk?

redux-thunk是一个redux的中间件,用来处理redux中的复杂逻辑,比如异步请求;

redux-thunk中间件可以让action创建函数先不返回一个action对象,而是返回一个函数;

138.redux-sagaredux-thunk 之间有什么区别?

Redux ThunkRedux Saga都负责处理副作用。在大多数场景中,Thunk 使用Promises来处理它们,而 Saga 使用Generators。Thunk 易于使用,因为许多开发人员都熟悉 Promise,Sagas/Generators 功能更强大,但您需要学习它们。但是这两个中间件可以共存,所以你可以从 Thunks 开始,并在需要时引入 Sagas。

139.如何向 Redux 添加多个中间件?

你可以使用applyMiddleware()

例如,你可以添加redux-thunklogger作为参数传递给applyMiddleware()

import { createStore, applyMiddleware } from 'redux'
const createStoreWithMiddleware = applyMiddleware(ReduxThunk, logger)(createStore)


140.如何在 Redux 中设置初始状态?

您需要将初始状态作为第二个参数传递给 createStore :

const rootReducer = combineReducers({
  todos: todos,
  visibilityFilter: visibilityFilter
})

const initialState = {
  todos: [{ id: 123, name: 'example', completed: false }]
}

const store = createStore(
  rootReducer,
  initialState
)

发布了29 篇原创文章 · 获赞 0 · 访问量 741

猜你喜欢

转载自blog.csdn.net/Jojorain/article/details/105522135