Как вызвать метод класса Screen/Component из заголовка реакции-навигации

Мне нужно вызвать метод класса SearchScreen из заголовка React Navigation.

Навигатор выглядит так:

  Search: {
    screen: SearchScreen,
    path: 'search/:query',
    navigationOptions: {
      title: 'Search',
      header: {
        right: (
          <MaterialCommunityIcons
            name="filter"
            onPress={() => {
              console.log(this);
            }}
            style={{marginRight: 15, color: 'white'}}
            size={24}
          />
        ),
      },
    }
  }

person AlejandroJS    schedule 21.02.2017    source источник
comment
Единственный способ, которым я добавил функциональность, — это добавить логику в сам компонент кнопки или значка и использовать действие сокращения, а не ссылаться на сам экран.   -  person MonkeyBonkey    schedule 22.02.2017


Ответы (4)


Я заставил это работать, выполнив:

// declare static navigationOptions in the Component
static navigationOptions = {
  title: 'Title',
  header: ({ state }) => ({
    right: (
      <MaterialCommunityIcons
        name="filter"
        onPress={state.params.handleFilterPress}
        style={{marginRight: 15, color: 'white'}}
        size={24}
      />
    ),
  }),
}

_handleFilterPress() {
  // do something
}


componentDidMount() {
  // set handler method with setParams
  this.props.navigation.setParams({ 
    handleFilterPress: this._handleFilterPress.bind(this) 
  });
}

person AlejandroJS    schedule 01.03.2017
comment
@KartikeyaBaleneni попробуйте navigation.setParams для componentWillMount, выдает ли это какую-либо ошибку? - person AlejandroJS; 03.04.2018
comment
Этот шаблон сработал для меня, и я создал простой HOC, чтобы упростить его реализацию — npmjs.com/package/react-navigation-underscore - person James Armstead; 09.06.2018
comment
Вы также установили params в своем навигаторе, иначе он будет неопределенным @Kartikeya - person オスカー; 10.03.2019

Я решил проблему следующим образом:

static navigationOptions = ({ navigation }) => {
    return {
        headerRight: () => (

            <TouchableOpacity
                onPress={navigation.getParam('onPressSyncButton')}>
                <Text>Sync</Text>
            </TouchableOpacity>
        ),
    };
};

componentDidMount() {
    this.props.navigation.setParams({ onPressSyncButton: this._onPressSyncButton });
}

_onPressSyncButton = () => {
     console.log("function called");
}
person Waqar UlHaq    schedule 06.11.2019

Решение хуков с FunctionComponent, useState и useEffect

См. официальные документы (https://reactnavigation.org/docs/en/header-buttons.html#header-interaction-with-its-screen-component) это делается следующим образом:

class HomeScreen extends React.Component {
  static navigationOptions = ({ navigation }) => {
    return {
      headerTitle: <LogoTitle />,
      headerRight: (
        <Button
          onPress={navigation.getParam('increaseCount')}
          title="+1"
          color="#fff"
        />
      ),
    };
  };

  componentDidMount() {
    this.props.navigation.setParams({ increaseCount: this._increaseCount });
  }

  state = {
    count: 0,
  };

  _increaseCount = () => {
    this.setState({ count: this.state.count + 1 });
  };

  /* later in the render function we display the count */
}

Однако я не мог заставить это работать при работе с хуками API. Мои переменные состояния всегда были undefined, но после того, как я подумал о том, как реализован API хуков, все это обрело смысл, поэтому решение заключалось в том, чтобы обновлять параметр навигации каждый раз, когда изменялась важная переменная состояния:

const [count, setCount] = useState(0);

useEffect(() => {
    props.navigation.setParams({ increaseCount });
}, [count]);

const increaseCount = () => setCount(count + 1);
person kentrh    schedule 10.07.2019
comment
Я получаю бесконечный цикл при попытке установить параметры с помощью useEffect. Можете ли вы поделиться своим полным примером кода? - person ; 22.07.2019
comment
@Jason Я думаю, может быть, это может произойти, если у вас есть другие функции изменения состояния в функции useEffect. Я исправил это, проверив, нужно ли его обновлять и обновлять соответственно. Например, у меня есть объект User, который загружается в useEffect, и он загружается только в том случае, если объект undefined, а затем продолжает обновление props.navigation.setParams({ increaseCount }); Извините за задержку, и, пожалуйста, дайте мне знать, если вы все еще хотите, чтобы я изменил ответ на мой конкретный версия. - person kentrh; 23.08.2019

Я столкнулся с той же проблемой и смог решить ее по ссылкам ниже.

class MyScreen extends React.Component {
    static navigationOptions = {
        header: {
            right: <Button title={"Save"} onPress={() => this.saveDetails()} />
        }
    };

    saveDetails() {
        alert('Save Details');
    }

    render() {
        return (
            <View />
        );
    }
}

Источник: проблемы React-Native 145

Ниже мой код

import React, { Component } from "react";
import {
  Container,
  Header,
  Item,
  Input,
  Icon,
  Button,
  Text,
  Left,
  Body,
  Right,
  Content,
  Spinner,
  List,
  ListItem
} from "native-base";
import { View, Image, StyleSheet, Keyboard } from "react-native";
import { connect } from "react-redux";
import {
  onClear,
  onSearchTextChanged,
  searchForProfiles
} from "../../actions/searchActions";

class SearchBar extends Component {
  constructor(props) {
    super(props);
  }

  render() {
    return (
      <Header searchBar rounded>
        <Button
          iconLeft
          style={{ paddingLeft: 0 }}
          light
          onPress={this.props.onBackPress}
        >
          <Icon style={{ marginLeft: 0, fontSize: 35 }} name="arrow-back" />
        </Button>
        <Item>
          <Icon name="ios-search" />
          <Input
            placeholder="Search"
            onChangeText={this.props.onChangeText}
            value={this.props.searchText}
          />
          <Button small transparent onPress={this.props.onClear}>
            <Icon name="ios-close" />
          </Button>
        </Item>
        <Button transparent onPress={this.props.onSearch}>
          <Text>Search</Text>
        </Button>
      </Header>
    );
  }
}

class SearchWorld extends Component {
  static navigationOptions = ({ navigation }) => ({
    left: null,
    header: () => {
      const { state } = navigation;
      return (
        <SearchBar
          onBackPress={() => navigation.goBack()}
          onChangeText={text => {
            state.params.onChangeText(text);
          }}
          onSearch={state.params.onSearch}
          onClear={state.params.onClear}
          searchText={state.params.searchText}
        />
      );
    }
  });

  onChangeText = text => {
    this.props.navigation.setParams({
      ...this.props.navigation.state,
      searchText: text
    });
    this.props.onSearchTextChanged(text);
  };

  onSearch = () => {
    Keyboard.dismiss();
    const profile = { search: "test" };
    const token = this.props.token;
    this.props.searchForProfiles(token, profile);
  };

  onClear = () => {
    this.props.onClear();
    this.props.navigation.setParams({
      ...this.props.navigation.state,
      searchText: ""
    });
  };

  componentDidMount() {
    this.props.navigation.setParams({
      onChangeText: this.onChangeText,
      onSearch: this.onSearch,
      onClear: this.onClear,
      searchText: this.props.searchText
    });
  }

  render() {
    const { searchResults } = this.props;
    let items = [];
    if(searchResults && searchResults.data && searchResults.data.length > 0) {
      items = [...searchResults.data];
    }
    return this.props.loading ? (
      <Container style={{ alignItems: "center", justifyContent: "center" }}>
        <Spinner color="#FE6320" />
      </Container>
    ) : (
      <Container>
        <Content>
          <List
            style={{}}
            dataArray={items}
            renderRow={item => (
              <ListItem style={{ marginLeft: 0}}>
                <Text style={{paddingLeft: 10}}>{item.password}</Text>
              </ListItem>
            )}
          />
        </Content>
      </Container>
    );
  }
}

const mapStateToProps = state => {
  const { token } = state.user;
  const { searchText, searchResults, error, loading } = state.searchReaducer;

  return {
    token,
    searchText,
    searchResults,
    error,
    loading
  };
};

export default connect(mapStateToProps, {
  onClear,
  onSearchTextChanged,
  searchForProfiles
})(SearchWorld);
person Ashok R    schedule 18.11.2017