Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.0k views
in Technique[技术] by (71.8m points)

reactjs - Get ref from connected redux component withStyles

I have this export of a working component:

export default connect(
    mapStateToProps, actions,
    null, { withRef: true, forwardRef: true }
  )(withTheme()(withStyles(styles)(MainMenu)));

And its call:

<MainMenu 
  ref={(connectedMenu) => this.menuRef = connectedMenu.getWrappedInstance()} 
  user={user} 
/>

I've expected to get a MainMenu ref, but I keep getting WithTheme object instead.

I've also tried to get through innerRef, but got the following errors:

TypeError: connectedMenu.getWrappedInstance is not a function
TypeError: Cannot read property 'getWrappedInstance' of null

Before all of that I've tried that React.createRef() format, but it didn't worked.

How do I get this ref?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Assuming you are using v4 of Material-UI, your syntax for withTheme is incorrect. In v4 the first set of parentheses was removed.

Instead of

withTheme()(YourComponent)

you should have

withTheme(YourComponent)

Below is code from a modified version of the react-redux todo list tutorial that shows the correct syntax. I've included here the two files that I changed (TodoList.js and TodoApp.js), but the sandbox is a fully working example.

In TodoApp, I use the ref on TodoList to get and display its height. The displayed height will only get updated if TodoApp re-renders, so I've included a button to trigger a re-render. If you add a couple todos to the todo list, and then click the re-render button, you will see that the new height of the list is displayed (showing that the ref is fully working).

In TodoList, I'm using withStyles to add a blue border around the todo list to show that withStyles is working, and I'm displaying the primary color from the theme to show that withTheme is working.

TodoList.js

import React from "react";
import { connect } from "react-redux";
import Todo from "./Todo";
import { getTodosByVisibilityFilter } from "../redux/selectors";
import { withStyles, withTheme } from "@material-ui/core/styles";
import clsx from "clsx";

const styles = {
  list: {
    border: "1px solid blue"
  }
};
const TodoList = React.forwardRef(({ todos, theme, classes }, ref) => (
  <>
    <div>theme.palette.primary.main: {theme.palette.primary.main}</div>
    <ul ref={ref} className={clsx("todo-list", classes.list)}>
      {todos && todos.length
        ? todos.map((todo, index) => {
            return <Todo key={`todo-${todo.id}`} todo={todo} />;
          })
        : "No todos, yay!"}
    </ul>
  </>
));

const mapStateToProps = state => {
  const { visibilityFilter } = state;
  const todos = getTodosByVisibilityFilter(state, visibilityFilter);
  return { todos };
};
export default connect(
  mapStateToProps,
  null,
  null,
  { forwardRef: true }
)(withTheme(withStyles(styles)(TodoList)));

TodoApp.js

import React from "react";
import AddTodo from "./components/AddTodo";
import TodoList from "./components/TodoList";
import VisibilityFilters from "./components/VisibilityFilters";
import "./styles.css";

export default function TodoApp() {
  const [renderIndex, incrementRenderIndex] = React.useReducer(
    prevRenderIndex => prevRenderIndex + 1,
    0
  );
  const todoListRef = React.useRef();
  const heightDisplayRef = React.useRef();
  React.useEffect(() => {
    if (todoListRef.current && heightDisplayRef.current) {
      heightDisplayRef.current.innerHTML = ` (height: ${
        todoListRef.current.offsetHeight
      })`;
    }
  });
  return (
    <div className="todo-app">
      <h1>
        Todo List
        <span ref={heightDisplayRef} />
      </h1>
      <AddTodo />
      <TodoList ref={todoListRef} />
      <VisibilityFilters />
      <button onClick={incrementRenderIndex}>
        Trigger re-render of TodoApp
      </button>
      <div>Render Index: {renderIndex}</div>
    </div>
  );
}

Edit Todo App with Redux


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...